简介
web过滤器
过滤器是指拦截请求,并对传给被请求资源的ServletRequest或ServletResponse进行处理的一个对象。
过滤器可用于登录、加密和解密、对话检查、图片转换等待。过滤器可以配置拦截一个或者多个资源
1.Filter API
过滤器必须实现javax.servret.Filter接口,这个接口暴露三个生命周期方法:init,doFilter,destroy
当过滤器启动服务时,Servlet容器就会调用init方法。这个方法指调用一次
void init(FilterConfig filterConfig)
filterConfig可用于获取ServletContext对象,或者获取初始化属性(getInitParameter)
doFilter方法时过滤器核心
void doFilter(ServletRequest request ,ServletResponse response,FilterChain chain)
可以在ServletRequest 中添加属性,或者在ServletResponse添加一个标头
也可以获取HttpServletRequest对象
doFilter方法实现中的最后一行代码应该时调用FilterChain中的doFilter(request,response)方法
表示放行,通常会引发下一个过滤器被调用。
void destroy()
这个方法在过滤器即将终止服务之前,有servlet容器调用
2.过滤器的配置
确定要拦截哪些资源 (urlPatterns value)
要传给init方法的启动初始值(initParams) 可通过getParameterNames 和getParameter方法来获取
给过滤器七个名字(filterName)
可以通过@webFilter注解 和部署描述符中声明
1.过滤器创建与配置
/**
*@WebFilter 用于将一个类声明为过滤器
*/
@WebFilter("/MyFilter")
public class MyFilter implements Filter {
//创建实例
public MyFilter(){
System.out.println("1.创建过滤器实例");
}
//初始化方法,在服务器启动时执行
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2.执行过滤器初始化方法");
//获取过滤器在web.xml中配置的所有初始化参数
Enumeration<String> enums = filterConfig.getInitParameterNames();
while(enums.hasMoreElements()){
//获取所有参数
String name = enums.nextElement();
//获取名称对应的值
String value = filterConfig.getInitParameter(name);
System.out.println(name+":"+value);
}
}
//过滤器业务处理方法,在请求到达servlet之前县进入此方法处理公用的业务逻辑操作
//FilterChain 过滤器链参数;一个个过滤器形成一个执行链
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("3.执行过滤器业务处理方法");
//执行下一个过滤器或放行(去到servlet)
chain.doFilter(request, response);
//如果有下一个过滤器,进入下一个过滤器,否则就执行访问servlet
System.out.println("5.Servlet处理完成,又回到过滤器");
}
//销毁过滤器实例时候调用
@Override
public void destroy() {
System.out.println("6.销毁过滤器实例");
}
}
过滤器创建与配置:web.xml
<!-- 过滤器声明 -->
<filter>
<!-- 过滤器的名称 -->
<filter-name>MyFilter</filter-name>
<!-- 过滤器的完整类名:包名+类名 -->
<filter-class>com.mrkj.ygl.filter.MyFilter</filter-class>
<!-- 设置初始化参数 -->
<init-param>
<!-- 参数名 -->
<param-name>***</param-name>
<!-- 参数值 -->
<param-value>***</param-value>
</init-param>
</filter>
<!-- 过滤器映射 -->
<filter-mapping>
<!-- 过滤器的名称 -->
<filter-name>MyFilter</filter-name>
<!-- 过滤器URL映射:/* 映射所有文件 -->
<url-pattern>/*</url-pattern>
<!--
1.拦截所有资源
<url-pattern>/*</url-pattern>
-->
<!-- 2.拦截指定的jsp -->
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/list.jsp</url-pattern>
<url-pattern>*.jsp</url-pattern>
<!-- 3.根据servlet的内部名称拦截 -->
<servlet-name>IndexServlet</servlet-name>
<url-pattern>/IndexServlet</url-pattern>
<!--
4.拦截指定的类型
REQUEST:默认拦截的类型
FORWARD:拦截转发
INCLUDE:拦截包含的页面
ERROR:拦截声明式异常
-->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
<!-- 过滤器URL映射 -->
</filter-mapping>
2.字符编码过滤器
@WebFilter(asyncSupported = true, urlPatterns = { "/CharactorFilter" })
public class CharactorFilter implements Filter {
String encoding = null;
public CharactorFilter() {
}
public void init(FilterConfig fConfig) throws ServletException {
encoding = fConfig.getInitParameter("encoding");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(encoding != null) {
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
}
chain.doFilter(request, response);
}
public void destroy() {
encoding = null;
}
}
字符编码过滤器:web.xml
<filter>
<filter-name>CharactorFilter</filter-name>
<filter-class>com.mrkj.ygl.filter.CharactorFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharactorFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.网站访问计数器
@WebFilter(asyncSupported = true, urlPatterns = { "/CountFilter" })
public class CountFilter implements Filter {
//来访数量
private int count;
public CountFilter() {
}
public void init(FilterConfig fConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
count++; //访问数量自增
//将ServletRequest转换为HttpServletRequest
HttpServletRequest req = (HttpServletRequest) request;
//将来访数量值放入到ServletContext
ServletContext context = req.getSession().getServletContext();
context.setAttribute("count", count);
chain.doFilter(request, response); //向下传递过滤器
}
public void destroy() {
}
}
用于对网站访问的人数进行计数
网站访问计数器:web.xml
<filter>
<filter-name>CountFilter</filter-name>
<filter-class>com.mrkj.ygl.filter.CountFilter</filter-class>
<init-param>
<param-name>count</param-name>
<param-value>5000</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CountFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
对应网站:index.jsp
<h2>
欢迎光临,<br>
你是本站第【<%=application.getAttribute("count") %>】位访客!
</h2>
4.无效数据处理
package com.mrkj.ygl.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class EncodingFilter implements Filter {
// 初始化无效数据
private List<String> dirtyData;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 模拟几个数据,过滤词汇
dirtyData = new ArrayList<String>();
dirtyData.add("nmd");
dirtyData.add("炸使馆");
dirtyData.add("买了否认");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// 转型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 一、处理公用业务
request.setCharacterEncoding("UTF-8"); // POST提交有效
response.setContentType("text/html;charset=UTF-8");
HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance(
// 指定当前使用的累加载器
request.getClass().getClassLoader(),
// 对目标对象实现的接口类型
new Class[]{HttpServletRequest.class},
// 事件处理器
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 定义方法返回值
Object returnValue = null;
// 获取方法名
String methodName = method.getName();
// 判断:对getParameter方法进行GET提交中文处理
if ("getParameter".equals(methodName)) {
// 获取请求数据值【 <input type="text" name="userName">】
String value = request.getParameter(args[0].toString()); // 调用目标对象的方法
// 获取提交方式
String methodSubmit = request.getMethod(); // 直接调用目标对象的方法
// 判断如果是GET提交,需要对数据进行处理 (POST提交已经处理过了)
if ("GET".equals(methodSubmit)) {
if (value != null && !"".equals(value.trim())){
// 处理GET中文
value = new String(value.getBytes("ISO8859-1"),"GB2312");
}
}
// 中文数据已经处理完: 下面进行无效数据过滤
//【如何value中出现dirtyData中数据,用****替换】
for (String data : dirtyData) {
// 判断当前输入数据(value), 是否包含无效数据
if (value.contains(data)){
value = value.replace(data, "*****");
}
}
// 处理完编码、无效数据后的正确数据
return value;
}else {
// 执行request对象的其他方法
returnValue = method.invoke(request, args);
}
return returnValue;
}
});
//传入代理对象
chain.doFilter(proxy, response);
}
@Override
public void destroy() {
}
}
无效数据处理:web.xml
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.mrkj.ygl.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.访问权限过滤器
防止用户直接输入URL直接访问资源。
访问权限过滤器:web.xml
@WebFilter(asyncSupported = true, urlPatterns = { "/LoginFilter" })
public class LoginrFilter implements Filter {
public UserFilter() {
}
public void init(FilterConfig fConfig) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取Session
HttpSession session = req.getSession();
// 获取Session中存储的对象s
Object o = session.getAttribute("LoginSession");
// 获取当前请求的URI
String url = req.getRequestURI();
// 判断Session中的对象是否为空;判断请求的URI是否为不允许过滤的URI
if (o == null
/*
indexOf() 方法可返回数组中某个指定的元素位置。
该方法将从头到尾地检索数组,看它是否含有对应的元素。开始检索的位置在数组 start 处或数组的开头(没有指定 start 参数时)。如果找到一个 item,则返回 item 的第一次出现的位置。开始位置的索引为 0。
如果在数组中没找到指定元素则返回 -1。
*/
&& !url.endsWith("login.jsp") // 对URL地址为此结尾的文件不过滤
&& url.indexOf("login.do") < 0 // 对URL地址中包含此字符串的文件不过滤
&& url.indexOf("/images/") < 0) {
res.sendRedirect(req.getContextPath() + "/login.jsp");
} else {
chain.doFilter(request, response);
res.setHeader("Cache-Control","no-store");
res.setDateHeader("Expires",0);
res.setHeader("Pragma","no-cache");
res.flushBuffer();
}
}
}
<filter>
<filter-name>UsersFilter</filter-name>
<filter-class>com.mrkj.ygl.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UsersFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6.用户登录过滤
public class SessionFilter extends OncePerRequestFilter{
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(
* javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
*/
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//request.getSession().setAttribute("loginedUser", "ssss");
// 不过滤的uri
String[] notFilter = new String[] { "login.jsp", "index.jsp" };
// 请求的uri
String uri = request.getRequestURI();
// uri中包含background时才进行过滤
if (uri.indexOf("do") != -1) {
// 是否过滤
boolean doFilter = true;
for (String s : notFilter) {
if (uri.indexOf(s) != -1) {
// 如果uri中包含不过滤的uri,则不进行过滤
doFilter = false;
break;
}
}
if (doFilter) {
// 执行过滤
// 从session中获取登录者实体
Object obj = request.getSession().getAttribute("loginedUser");
if (null == obj) {
// 如果session中不存在登录者实体,则弹出框提示重新登录
// 设置request和response的字符集,防止乱码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String loginPage = "login-old.jsp";
StringBuilder builder = new StringBuilder();
builder.append("<script type=\"text/javascript\">");
builder.append("alert('网页过期,请重新登录');");
builder.append("window.top.location.href='");
builder.append(loginPage);
builder.append("';");
builder.append("</script>");
out.print(builder.toString());
} else {
// 如果session中存在登录者实体,则继续
filterChain.doFilter(request, response);
}
} else {
// 如果不执行过滤,则继续
filterChain.doFilter(request, response);
}
} else {
// 如果uri中不包含background,则继续
filterChain.doFilter(request, response);
}
}
//在web.xml中配置..
}
web.xml
<filter>
<filter-name>sessionFilter</filter-name>
<filter-class>com.ssm.student.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>