web三大组件:Servlet控制器,Filter过滤器,Listener监听器
一。过滤器
1.1简介:
为什么要使用过滤器?
在我们实际项目中,我们对访问某些资源的请求需要进条件的筛选、过滤。当这个请求满足特定的情况,才能让这个
请求访问目标资源,如果不满足条件,就不让访问目标资源。比如说:对于访问管理员功能的请求,我们应该对这样
的请求进行管理员权限的判断。如果当前用户拥有管理员权限,可以访问。反之不可以。我们
java
开发中需要很多这
样过滤功能的操作,所以需要使用过滤器。
过滤器定义:
Filter :是 Java 中预先定义好了的接口,可以过滤不同的内容,具体怎么过滤,需要使用者定义一个实现类,然后实现接口中的过滤方法,在方法中书写过滤的条件。 fifilter 是对客户端访问资源的过滤,符合条件放行,不符合条件不放行
web中的过滤器
当用户访问服务器资源时,过滤器将请求拦截下来,完成一些通用的操作
应用场景:登录验证,统一字符编码,敏感字符串拦截等
1.2过滤器入门:
- Filter的Api介绍:
总结:
- 我们创建一个过滤器的话需要实现Filter这个接口
- doFilter方法执行过滤器的功能
- 使用步骤
1.
编写一个
Servlet,
路径为
/demo
2.
创建一个类实现过滤器接口
3. xml
方式或者注解方式配置过滤器拦截的请求路径(
urlPatterns = "/demo1"
)
4.
在
doFilter
方法中书写过滤任务
5. FilterChain.doFilter
方法放行
注意:过滤器Filter方法默认拦截请求,如果需要经过过滤器之后,可以继续访问资源,要使用filterChain对象的doFilter方法放行
- xml配置方式:
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() {
}
}
<?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.wsl.a_quick.QuickFilter</filter-class>
</filter>
<!--配置filter拦截路径-->
<filter-mapping>
<filter-name>QuickFilter</filter-name>
<url-pattern>/quick.jsp</url-pattern>
</filter-mapping>
</web-app>
- 注解配置
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(filterName = "QuickFilter",urlPatterns = "/quick.jsp")
// @WebFilter(urlPatterns = "/quick.jsp")
// @WebFilter(value = "/quick.jsp")
@WebFilter("/quick.jsp")
public class QuickFilter implements Filter {
// 代码细节省略....
}
1.3 过滤器的执行流程
图解如下:
1.4 过滤器的生命周期:
指一个对象从创建到销毁的过程:
// 初始化方法
public void init(FilterConfig config);
// 执行拦截方法
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain);
// 销毁方法
public void destroy();
创建
服务器启动项目加载,创建filter对象,执行init方法(只执行一次)
运行(过滤拦截)
用户访问被拦截目标资源时,执行doFilter方法
销毁
服务器关闭项目卸载时,销毁filter对象,执行destroy方法(只执行一次)
注意:
过滤器一定是优先于servlet创建的
Api方法详解:
init方法
doFilter方法
destory方法
总结:
1.
当服务器启动的时候,过滤器就被初始化了,执行过滤器的
init
方法
2.
每当一个请求的路径是满足过滤器的配置路径,那么就会执行一次过滤器的
doFilter
方法
3.
当服务器停止的时候,销毁过滤器,执行过滤器的
destory
方法
// @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.wsl.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>
1.5 映射路径,拦截路径
在编写的
Filter
时
,
都是对某一个
Servlet
进行的过滤
,
其实我们是可以通过配置
Filter
的映射路径
,
从而可
以使用一个过滤器拦截不同的请求路径
可以指定过滤器的拦截路径来定义拦截目标资源的范围 :
* 精准匹配
用户访问指定目标资源(/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() {
}
}
1.6 拦截方式
在开发时,我们可以指定过滤器的拦截方式来处理不同的应用场景,比如:只拦截从浏览器直接发送过来的请求,或者拦截内部转发的请求
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.wsl.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() {
}
}
1.7过滤器链
们 java 代码中,有时需要对同一个请求,进行多次不同业务的过滤,所以我们 java 代码中需要多个过滤器。只有所有的过滤器都对请求进行了放行,请求才能访问到目标资源,只要多个过滤器中只有一个过滤器不放行请求,那么这个请求都不能够访问到目标资源。多个过滤器组成的一个整体我们称为过滤器链。而且,过滤器链中的过滤器是一个一个的执行的,一个过滤器执行完毕之后,会执行下一个过滤器,后面没有过滤器了,才会访问到目标资源。只要其中一个过滤器没有放行,那么这个过滤器后面的过滤器也都不会执行了。
过滤器链中的多个过滤器的执行顺序
- 在xml配置方式中,过滤器的执行顺序是通过各自的标签在web.xml的顺序执行的,谁在上面谁先执行.
- 在注解配置方式中,过滤器的执行顺序是通过过滤器的类名的字符顺 序决定的.
执行顺序演示:
需求
用户访问目标资源 show.jsp时,经过 FilterA FilterB
* 过滤器链执行顺序 (先进后出)
1.用户发送请求
2.FilterA拦截,放行
3.FilterB拦截,放行
4.执行目标资源 show.jsp
5.FilterB增强响应
6.FilterA增强响应
7.封装响应消息格式,返回到浏览器
* 过滤器链中执行的先后问题....
配置文件
谁先声明,谁先执行
<filter-mapping>
注解【不推荐】
根据过滤器类名进行排序,值小的先执行
FilterA FilterB 进行比较, FilterA先执行...
过滤器链的执行流程图如下:
注意:
在我们以后开发中 , 过滤器一般都是别人写好的 , 我们只需要配置下即可 , 因为过滤器是别人写好的 , 我
们一般不会去修改人家的源代码 , 在类上添加注解 ,所以以后过滤器的配置一般采用xml方式.
1. 如果是自己定义的filter,不要执行先后问题的话,可以使用注解开发...2. 如果是第三方jar提供的filter,在web.xml进行配置
二。案例
网站统一编码问题:
// @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.wsl.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>
过滤字符串
1.
jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>论坛留言</title>
</head>
<body>
<h2>论坛留言</h2>
<form action="${pageContext.request.contextPath}/WordsServlet" method="post">
<textarea name="content" id="" cols="30" rows="10"></textarea>
<input type="submit" value="请留言">
</form>
</body>
</html>
过滤器Filter
@WebFilter("/WordsServlet")
public class WordsFilter implements Filter {
private List<String> wordsList;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String content = request.getParameter("content");
System.out.println(content);
for (String word : wordsList) {
if (content.contains(word)){
response.getWriter().write("你输入的词汇敏感,请重新输入");
return;
}
}
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
System.out.println("=======WordsFilter=========过滤器=================");
Properties properties = new Properties();
InputStream words = this.getClass().getResourceAsStream("/words.properties");
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(words, "utf-8"));
properties.load(bufferedReader);
} catch (IOException e) {
e.printStackTrace();
}
String keywords = properties.getProperty("keywords");
// String keywords = words.getString("keywords");
List<String> wordsList = Arrays.asList(keywords.split(","));
this.wordsList = wordsList;
}
}
@WebServlet("/WordsServlet")
public class WordsServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String content = request.getParameter("content");
response.getWriter().write("您留言为:"+content);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2.增强过滤器
public class HttpMyRequest extends HttpServletRequestWrapper {
private List<String> wordsList;
public HttpMyRequest(HttpServletRequest request,List<String> list) {
super(request);
this.wordsList =list;
}
@Override
public String getParameter(String name) {
String content = super.getParameter(name);
for (String word : wordsList) {
if (content.contains(word)){
String flagStr ="";
for (int i = 0; i < word.length(); i++) {
flagStr+="*";
}
content = content.replaceAll(word,flagStr);
}
}
return content;
}
}
@WebFilter("/WordsProServlet")
public class WordsProFilter implements Filter {
private List<String> wordsList;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
HttpMyRequest httpMyRequest = new HttpMyRequest(request, wordsList);
String content = httpMyRequest.getParameter("content");
System.out.println("==content=="+content);
chain.doFilter(httpMyRequest, response);
}
public void init(FilterConfig config) throws ServletException {
System.out.println("=======WordsProFilter=========过滤器=================");
Properties properties = new Properties();
InputStream words = this.getClass().getResourceAsStream("/words.properties");
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(words, "utf-8"));
properties.load(bufferedReader);
} catch (IOException e) {
e.printStackTrace();
}
String keywords = properties.getProperty("keywords");
System.out.println("=======WordsProFilter====="+keywords+"======");
List<String> wordsList = Arrays.asList(keywords.split(","));
this.wordsList = wordsList;
}
}
剩下的Servlet和1的Servlet一样即可。重要的是过滤器方面、
properties文件
words.properties
keywords=傻叉,你大爷的,SB
经验分享:
使用浏览器时报异常如下:
mvc模式总结: