FIlter作用
过滤器JavaWeb三大组件之一,它与Servlet很相似!不它过滤器是用来拦截请求的,而不是处理请求的。
当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter不“放行”,那么就不会执行用户请求的Servlet。
其实可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码。
FIlter实现步骤
1.创建AFilter类实现javax.servlet.Filter接口
2.添加@WebFilter("/*")注解或者添加web.xml配置
<filter>
<filter-name>AFilter</filter-name>
<filter-class>com.yuan.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>/*<!--表示连接所有请求,剩下的就不说明啦,要学会自己看懂哦--></url-pattern>
</filter-mapping>
3.已经完成了
4.@WebFilter参数说明
编写简单一个Filter
package com.yuan.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class AFilter implements Filter {
/**
* 初始化 创建后立即执行
*
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("AFilter出生啦");
}
/**
* 每次过滤时都会执行
*
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//访问时过滤
System.out.println("拦截!留下买路财");
//放行
chain.doFilter(request,response);
//响应时过滤
System.out.println("你又~回来啦?");
}
/**
* 销毁前立即执行
*/
@Override
public void destroy() {
System.out.println("AFilter去世啦");
}
}
FIlter说明
Filter是单例的!
void init(FilterConfig)
创建之后,马上执行;Filter会在服务器启动时就创建!
FilterConfig-->与ServletConfig相似
- 获取初始化参数:getInitParameter()
- 获取过滤器名称:getFilterName()
- 获取appliction:getServletContext()
void destory()
销毁之前执行!在服务器关闭时销毁void doFilter(ServletRequest,ServletResponse,FilterChain)
每次过滤时都会执行
FilterChain
doFilter(ServletRequest, ServletResponse):放行!
执行目标资源就相当于调用了目标Servlet的service()方法!,或是执行下一个过滤器!如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器!
多个过滤器执行顺序
1.<filter-mapping>的配置顺序决定了过滤器的执行顺序!
2.过滤时遵守先进先出
过滤器的N种拦截方式
<dispatcher>REQUEST</dispatcher>默认的!
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
@WebFilter(value = "/CServlet",
dispatcherTypes = {
DispatcherType.ASYNC,//异步
DispatcherType.ERROR,//错误
DispatcherType.FORWARD,//转发
DispatcherType.INCLUDE,//包含
DispatcherType.REQUEST})//请求
public class AFilter implements Filter {}
应用场景
执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行,只是在目标资源执行之前做一些准备工作
通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用;
在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理;
设置目标资源
/:所有资源
/xx/xx/ :xx/xx/下的所有资源
/aaa/bbb/ccc/Servlet:具体AServlet
案例
案例一【分ip统计网站的访问次数】
分析
统计工作需要在所有资源之前都执行,那么就可以放到Filter中了。
我们这个过滤器不做拦截操作!因为我们只是用来做统计的。
用什么东西来装载统计的数据。Map<String,Integer>
整个网站只需要一个Map即可!
Map什么时候创建(使用ServletContextListener,在服务器启动时完成创建,并只在到ServletContext中),Map保存到哪里!(Map保存到ServletContext中!!!)
Map需要在Filter中用来保存数据
Map需要在页面使用,打印Map中的数据
代码实现
Listener
package com.yuan.web.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.HashMap;
import java.util.LinkedHashMap;
@WebListener()
public class CListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//1.创建ServletContext
ServletContext application = sce.getServletContext();
//2.Map
HashMap<String, Integer> ipMap = new LinkedHashMap<>();
//3.把Map保存到ServletContext中
application.setAttribute("ipMap",ipMap);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
Filter
package com.yuan.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.LinkedHashMap;
/**
* @author Yuan-9826
*/
@WebFilter("/*")
public class CFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.得到ServletContext中的IPMap
ServletContext application = req.getServletContext();
//2.获取客户端IP
String IP = req.getRemoteAddr();
//3.获得并操作Map
LinkedHashMap<String, Integer> ipMap = (LinkedHashMap<String, Integer>) application.getAttribute("ipMap");
if (ipMap.containsKey(IP)) {
int ipValue = ipMap.get(IP);
ipMap.put(IP, ++ipValue);
System.out.println("添加了map IP = " + IP + "次数 = " + ipValue);
} else {
ipMap.put(IP, 1);
System.out.println("添加了map IP = " + IP + "次数 = " + 1);
}
application.setAttribute("ipMap", ipMap);
//4.放行
chain.doFilter(req, resp);
}
@Override
public void destroy() {
}
}
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="y" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<html>
<body>
<h1>显示IP</h1>
<h1>${applicationScope.ipMap }</h1>
<table border="1" align="center" width="60%">
<tr>
<th>IP地址</th>
<th>次数</th>
</tr>
<c:forEach items="${applicationScope.ipMap }" var="entry">
<tr>
<td>${entry.key}</td><%--这里不知道为啥没显示出来--%>
<td>${entry.value}</td><%--这里不知道为啥没显示出来--%>
</tr>
</c:forEach>
</table>
</body>
</html>
效果
image.png案例二【粗粒度权限过滤】
只有文字描述步骤
游客、会员、管理员三个粒度
1.创建一个Fileter,过滤会员下的资源访问,这是保安1号 ,doFilter里检查session中权限标记,第一道检查工序,不是管理员=> 放行,第二道检查工序,不是会员=> 打回到登录/注册页面,如果是会员就放行!
2.创建一个Fileter,过滤管理员下的资源访问,这是保安2号 ,doFilter里检查session中权限标记,查看是不是管理员,不是管理员=>打回到登录/注册页面,如果是管理员就放行!
案例三【解决全站字符乱码(POST和GET中文编码问题)】
工具类
package com.yuan.encoding;
import java.io.UnsupportedEncodingException;
/**
* 编码转换
*/
public class EncodeingUtils {
/**
* iso-8859-1 转成 utf-8
*
* @param code
* @return
*/
public static String i2u(String code) {
try {
return new String(code.getBytes("iso-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
new RuntimeException("转码失败");
return null;
}
}
/**
* iso-8859-1 转成 gbk
*
* @param code
* @return
*/
public static String i2g(String code) {
try {
return new String(code.getBytes("iso-8859-1"), "gbk");
} catch (UnsupportedEncodingException e) {
new RuntimeException("转码失败");
return null;
}
}
/**
* gbk 转成 iso-8859-1
*
* @param code
* @return
*/
public static String g2i(String code) {
try {
return new String(code.getBytes("gbk"), "iso-8859-1");
} catch (UnsupportedEncodingException e) {
new RuntimeException("转码失败");
return null;
}
}
/**
* gbk 转成 utf-8
*
* @param code
* @return
*/
public static String g2u(String code) {
try {
return new String(code.getBytes("gbk"), "utf-8");
} catch (UnsupportedEncodingException e) {
new RuntimeException("转码失败");
return null;
}
}
/**
* utf-8 转成 iso-8859-1
*
* @param code
* @return
*/
public static String u2i(String code) {
try {
return new String(code.getBytes("utf-8"), "iso-8859-1");
} catch (UnsupportedEncodingException e) {
new RuntimeException("转码失败");
return null;
}
}
/**
* utf-8 转成 gbk
*
* @param code
* @return
*/
public static String u2g(String code) {
try {
return new String(code.getBytes("utf-8"), "gbk");
} catch (UnsupportedEncodingException e) {
new RuntimeException("转码失败");
return null;
}
}
}
package com.yuan.web.filter;
import com.yuan.encoding.EncodeingUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* 被掉包了的Request
*/
public class HttpRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
public HttpRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 处理编码问题
* @param name
* @return
*/
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
return EncodeingUtils.i2u(value);
}
}
package com.yuan.web.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 乱码过滤器
*/
public class EncodingFilter implements Filter {
private String GET = "GET";
private String POST = "POST";
private Integer version = 8;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("编码过滤器执行");
final String version = filterConfig.getInitParameter("tomcatVersion");
this.version = Integer.valueOf(version);
System.out.println(version);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
//处理post请求编码问题
req.setCharacterEncoding("utf-8");
/**
* tomcat1.8之后自己做了get请求的处理
*/
if (version < 8) {
System.out.println("Tomcat版本低于8 做GET请求处理");
//掉包request 和 HttpServletRequest
HttpServletRequest request = (HttpServletRequest) req;
//放行时
if (GET.equals(request.getMethod())) {
HttpRequest hr = new HttpRequest(request);
chain.doFilter(hr, res);
} else if (POST.equals(request.getMethod())) {
chain.doFilter(req, res);
}
}else {
chain.doFilter(req, res);
System.out.println("Tomcat版本不低于8 不做GET请求处理");
}
}
@Override
public void destroy() {
}
}
只要配置了这个过滤器 即可使用
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.yuan.web.filter.EncodingFilter</filter-class>
<init-param>
<param-name>tomcatVersion</param-name>
<param-value>8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
网友评论