回顾
1. el
从四大域对象中获取数据
语法:${键名}
练习
字符串
对象
list|数组
map
运算符
${not empty 键名} 非空判断
隐式对象
${pageContext.request.contextPath} 动态获取项目访问路径
2. jstl
目前只是用core核心库
if标签 判断,这哥们没有else功能
forEach标签
普通for
begin 起始值
end 结束值
step 步长
var 临时变量
增强for
items 集合
var 临时变量
varStatus 变量状态
index 索引
count 计数
3. 三层架构
这哥们是mvc的升级版
web层:与浏览器交互
service层:处理业务逻辑
dao层:与数据库交互
Filter
今日目标
* web的三大组件
servlet(控制器)
filter(过滤器)
这哥们可以拦截浏览器一切请求,做一些业务处理
listener(监听器)
一 概述
生活中的过滤器
净水器、空气净化器、地铁安检、山大王
web中的过滤器
当用户访问服务器资源时,过滤器将请求拦截下来,完成一些通用的操作
应用场景
如:登录验证、统一编码处理、敏感字符过滤
二 快速入门
2.1 xml配置
① 编写java类,实现filter接口
public class QuickFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* 此方法拦截用户请求
* @param servletRequest :请求对象
* @param servletResponse :响应对象
* @param filterChain :过滤器链(是否放行)
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("QuickFilter拦截了请求...");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
② 配置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">
<!--快速入门-->
<!--注册filter-->
<filter>
<filter-name>QuickFilter</filter-name>
<filter-class>cn.itcast.a_quick.QuickFilter</filter-class>
</filter>
<!--配置filter拦截路径-->
<filter-mapping>
<filter-name>QuickFilter</filter-name>
<url-pattern>/quick.jsp</url-pattern>
</filter-mapping>
</web-app>
2.2 注解配置
- 注意:玩注解的话,需要把web.xml中filter标签注释
① 编写java类,实现filter接口
public class QuickFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* 此方法拦截用户请求
* @param servletRequest :请求对象
* @param servletResponse :响应对象
* @param filterChain :过滤器链(是否放行)
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("QuickFilter拦截了请求...");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
② 配置@WebFilter
// @WebFilter(filterName = "QuickFilter",urlPatterns = "/quick.jsp")
// @WebFilter(urlPatterns = "/quick.jsp")
// @WebFilter(value = "/quick.jsp")
@WebFilter("/quick.jsp")
public class QuickFilter implements Filter {
// 代码细节省略....
}
三 工作原理
四 使用细节
4.1 生命周期
生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程
// 初始化方法
public void init(FilterConfig config);
// 执行拦截方法
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain);
// 销毁方法
public void destroy();
* 创建
服务器启动项目加载,创建filter对象,执行init方法(只执行一次)
* 运行(过滤拦截)
用户访问被拦截目标资源时,执行doFilter方法
* 销毁
服务器关闭项目卸载时,销毁filter对象,执行destroy方法(只执行一次)
* 补充:
过滤器一定是优先于servlet创建的
// @WebFilter(value = "/show.jsp",initParams = {@WebInitParam(name = "encode",value = "UTF-8")}) 设置初始化参数,一般不会在注解使用
public class LifecycleFilter implements Filter {
/*
filterConfig 它是filter的配置对象
注意作用:获取filter的初始化参数
*/
private String encode;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LifecycleFilter创建了...执行init方法");
encode = filterConfig.getInitParameter("encode");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LifecycleFilter拦截了请求...执行deFilter方法");
System.out.println("统一编码:" + encode);
// 放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("LifecycleFilter销毁了...执行destroy方法");
}
}
<!--生命周期和初始化参数-->
<filter>
<filter-name>LifecycleFilter</filter-name>
<filter-class>cn.itcast.b_detail.LifecycleFilter</filter-class>
<init-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LifecycleFilter</filter-name>
<url-pattern>/show.jsp</url-pattern>
</filter-mapping>
4.2 拦截路径
在开发时,我们可以指定过滤器的拦截路径来定义拦截目标资源的范围
* 精准匹配
用户访问指定目标资源(/show.jsp)时,过滤器进行拦截
* 目录匹配
用户访问指定目录下(/user/*)所有资源时,过滤器进行拦截
* 后缀匹配
用户访问指定后缀名(*.html)的资源时,过滤器进行拦截
* 匹配所有
用户访问该网站所有资源(/*)时,过滤器进行拦截
/*
* 精准匹配
用户访问指定目标资源(/show.jsp)时,过滤器进行拦截
* 目录匹配
用户访问指定目录下(/user/*)所有资源时,过滤器进行拦截
* 后缀匹配
用户访问指定后缀名(*.html)的资源时,过滤器进行拦截
* 匹配所有
用户访问该网站所有资源(/*)时,过滤器进行拦截
*/
// @WebFilter("/show.jsp") 精准匹配
// @WebFilter("/user/*") // 目录匹配
// @WebFilter("*.html") // 后缀匹配
@WebFilter("/*") // 匹配所有
public class UrlPatternFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
System.out.println("UrlPatternFilter拦截了请求...");
// 放行
chain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
4.3 拦截方式
在开发时,我们可以指定过滤器的拦截方式来处理不同的应用场景,比如:只拦截从浏览器直接发送过来的请求,或者拦截内部转发的请求
1. request(默认拦截方式)
浏览器直接发送请求时,过滤器拦截
2. forward
资源A转发到资源B时,过滤器拦截
资源A:ForwardServlet
资源B:show.jsp
3. 我们可以配置 二个同时存在...
① xml版本
public class ModeFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
System.out.println("ModeFilter拦截了请求.....");
// 放行
chain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
<!--拦截方式-->
<filter>
<filter-name>ModeFilter</filter-name>
<filter-class>cn.itcast.b_detail.ModeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ModeFilter</filter-name>
<url-pattern>/show.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
② 注解版本
@WebFilter(value = "/show.jsp",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
public class ModeFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
System.out.println("ModeFilter拦截了请求.....");
// 放行
chain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
4.4 过滤器链
在一次请求中,若我们请求匹配到了多个filter,通过请求就相当于把这些filter串起来了,形成了过滤器链
* 需求
用户访问目标资源 show.jsp时,经过 FilterA FilterB
* 过滤器链执行顺序 (先进后出)
1.用户发送请求
2.FilterA拦截,放行
3.FilterB拦截,放行
4.执行目标资源 show.jsp
5.FilterB增强响应
6.FilterA增强响应
7.封装响应消息格式,返回到浏览器
* 过滤器链中执行的先后问题....
配置文件
谁先声明,谁先执行
<filter-mapping>
注解【不推荐】
根据过滤器类名进行排序,值小的先执行
FilterA FilterB 进行比较, FilterA先执行...
4.5 注解和xml使用
1. 如果是自己定义的filter,不要执行先后问题的话,可以使用注解开发...
2. 如果是第三方jar提供的filter,在web.xml进行配置
五 综合案例
5.1 用户评论留言
需求
用户访问某论坛网站,可以对文章比赛等内容进行留言
5.1.1 需求分析
5.1.2 代码实现
① bbs.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>bbs</title>
</head>
<body>
<h3>LPL季后赛观看留言板</h3>
<hr>
<form action="${pageContext.request.contextPath}/WordsServlet" method="post">
<textarea name="content" id="" cols="30" rows="10"></textarea>
<input type="submit" value="请留言">
</form>
</body>
</html>
② WordsServlet
@WebServlet("/WordsServlet")
public class WordsServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.接收请求参数 content
String content = request.getParameter("content");
// 2.将结果响应到 浏览器
response.getWriter().write(content);
}
}
5.2 统一网站编码
需求
tomcat8.5版本中已经将get请求的中文乱码解决了,但是post请求还存在中文乱码
浏览器发出的任何请求,通过过滤器统一处理中文乱码
5.2.1 需求分析
5.2.2 代码实现
- 真实场景中,过滤器不会统一响应mime类型
// @WebFilter("/*")
public class EncodeFilter implements Filter {
private String encode;
public void init(FilterConfig config) throws ServletException {
encode = config.getInitParameter("encode");
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
// 类型向下转型
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 判断用户是否为post请求,才设置编码
if (request.getMethod().equalsIgnoreCase("post")) {
request.setCharacterEncoding(encode);
}
response.setContentType("text/html;charset="+encode); // 这个操作不太推荐.... 因为把所有响应类型给成了 html
// 放行
chain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
<!--统一网站编码-->
<filter>
<filter-name>EncodeFilter</filter-name>
<filter-class>cn.itcast.d_case.EncodeFilter</filter-class>
<init-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.3 非法字符拦截
需求
当用户发出非法言论的时候,提示用户言论非法警告信息
5.3.1 需求分析
5.3.2 代码实现
① 非法词库
② WordsFilter
@WebFilter("/WordsServlet")
public class WordsFilter implements Filter {
private List<String> wordList;
public void init(FilterConfig config) throws ServletException {
// 1.加载配置文件
/*
ResourceBundle这哥们 专门读取src目录下的properties配置文件,不需要写后缀名
*/
ResourceBundle words = ResourceBundle.getBundle("words");
// 2.读取keyword关键字内容
String keyword = words.getString("keyword"); // 傻叉,大爷的,二大爷的
// 3.split切割,转为list集合
wordList = Arrays.asList(keyword.split(","));
System.out.println("加载非法词库:"+wordList);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
// 向下转型
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 1.获取用户输入的值
String content = request.getParameter("content");
// 2.拦截非法内容,提示
for (String word : wordList) { // 遍历非法词库
if(content.contains(word)){ // 判断是否包含非法词汇
response.getWriter().write("你输入的词汇敏感,拦截了。。。");
return;
}
}
// 3.放行
chain.doFilter(request, response);
}
public void destroy() {
}
}
5.4 非法字符过滤
需求
当用户发出非法言论的时候,在servlet中输出的时候:用"*" 替代
你是个笨蛋 --> 你是个**
5.4.1 技术分析
// 对此方法进行增强....
request.getParameter(String name);
方案一:继承,无法对接口进行增强...
==方案二:代理==
方案三:装饰(包装),经典场景就是IO流
* 使用要求:
1. 包装类和被包装类实现同一个接口(或者继承同一个抽象类)
2. 包装类要有被包装类的对象引用
3. 对需要增强的方法重写
4. 对不需要增强的方法,执行原有的逻辑
/*
回顾装饰(器)模式
*/
public class TestDecorator {
public static void main(String[] args) {
Phone phone = new Lvjing(new Meiyan(new HuaWei()));
phone.take();
phone.call();
}
}
// 接口规范
interface Phone {
void take();
void call();
}
// 被包装类,一会对他增强
class HuaWei implements Phone {
@Override
public void take() {
System.out.println("3200W像素拍照");
}
@Override
public void call() {
System.out.println("打电话");
}
}
// 包装抽象类,做一个默认的实现,调用原有的功能
abstract class PhoneWrapper implements Phone {
private Phone phone;
public PhoneWrapper(Phone phone) {
this.phone = phone;
}
@Override
public void take() {
phone.take();
}
@Override
public void call() {
phone.call();
}
}
// 美颜增强
class Meiyan extends PhoneWrapper {
public Meiyan(Phone phone) {
super(phone);
}
@Override
public void take() {
// 调用拍照的原有功能
super.take();
System.out.println("美颜...");
}
}
// 滤镜增强
class Lvjing extends PhoneWrapper {
public Lvjing(Phone phone) {
super(phone);
}
@Override
public void take() {
super.take();// 原有功能
System.out.println("滤镜");
}
}
5.4.2 需求分析
5.4.3 代码实现
- 注意:需要将 WordsFilter过滤器的注解注释
① 自定义MyRequest
public class MyRequest extends HttpServletRequestWrapper {
// 非法词库
private List<String> wordList;
public MyRequest(HttpServletRequest request, List<String> wordList) {
super(request);
this.wordList = wordList;
}
// 对谁增强就重谁...
@Override
public String getParameter(String name) {
// 调用原有的功能,获取用户输入的值
String parameter = super.getParameter(name);
// 对非法词库过滤...
for (String word : wordList) {// 遍历
if (parameter.contains(word)) {
parameter = parameter.replaceAll(word, "***"); // 注意,替换完之后,进行覆盖...
}
}
return parameter;
}
}
② 编写WordsProFilter
@WebFilter("/WordsServlet")
public class WordsProFilter implements Filter {
private List<String> wordList;
public void init(FilterConfig config) throws ServletException {
// 1.加载配置文件
/*
ResourceBundle这哥们 专门读取src目录下的properties配置文件,不需要写后缀名
*/
ResourceBundle words = ResourceBundle.getBundle("words");
// 2.读取keyword关键字内容
String keyword = words.getString("keyword"); // 傻叉,大爷的,二大爷的
// 3.split切割,转为list集合
wordList = Arrays.asList(keyword.split(","));
System.out.println("加载非法词库:"+wordList);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
// 向下转型
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 对request对象进行包装 (过滤)
MyRequest requestPro = new MyRequest(request, wordList);
// 放行
chain.doFilter(requestPro, response);
}
public void destroy() {
}
}
- 课下作业,几个字几个*
附录
Filter模板设置
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
@javax.servlet.annotation.WebFilter("/${Entity_Name}")
public class ${Class_Name} implements javax.servlet.Filter {
public void init(javax.servlet.FilterConfig config) throws javax.servlet.ServletException {
}
public void doFilter(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse, javax.servlet.FilterChain chain) throws javax.servlet.ServletException, java.io.IOException {
// 放行
chain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
网友评论