当前位置: 首页 > java>阅读正文

servlet之filter拦截器

2021.12.21 朱丰华 1456 次 留下评论 3451字

filter是servlet的拦截器,能够在servlet处理前进行一些操作,比如设置编码、登录拦截等。(aop和filter非常类似)

配置filter

可以在web.xml配置

<filter>
	<filter-name>demo1</filter-name>
	<filter-class>com.52dixiaowo.web.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
	<filter-name>demo1</filter-name>
	<!-- 拦截路径 -->
	<url-pattern>/*</url-pattern>
</filter-mapping>

它的配置和servlet相似,只需要配置filter-class,和filter-mapping即可。

使用注解时,可使用@WebFilter

拦截方式

对于拦截路径, 下面有 4 种简单的方式, 还可以自由组合

  1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
  2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
  3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
  4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行

对于请求方式, 还可以选定哪种请求, 需要设置dispatcherTypes属性

  1. REQUEST:默认值。浏览器直接请求资源, 也可以同时设置多个值
  2. FORWARD:转发访问资源
  3. INCLUDE:包含访问资源
  4. ERROR:错误跳转资源
  5. ASYNC:异步访问资源

filter 过滤链的顺序问题: 如果是web.xml是按照<filter-mapping>的顺序, 而注解则是类名字符串大小, 比如 AFilter 比 BFilter先拦截.

关键方法 : doFilter

使用 doFilter 方法, 写上你要处理的逻辑代码, 该方法三参数, request, response, filterchain, 分别代表请求对象, 响应对象, 以及过滤链对象

其中 filterchain 对象, 有一个方法, filterChain.doFilter(servletRequest,servletResponse); 表示放行, 在它之前的代码表示对请求的处理, 在它之后的代码表示对响应的处理

对于 filter 的另外 2 个方法, init 和 destroy 表示web容器启动和销毁的处理

统一编码

如果使用get请求, 是不会乱码的, 而post有可能乱码, 可以使用filter设置统一编码

先 new 一个 class , 名称叫 EncodingFilter , 并拷贝如下代码

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 解决全站乱码问题,处理所有的请求
 */
@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {
        //将父接口转为子接口
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) rep;
        //获取请求方法
        String method = request.getMethod();
        //解决post请求中文数据乱码问题, get不会乱码
        if(method.equalsIgnoreCase("post")){
            request.setCharacterEncoding("utf-8");
        }
        //处理响应乱码, 仅设置响编码,而不是 setContentType
        response.setCharacterEncoding("utf-8");
        filterChain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

注意,上述代码设置了response编码,对于html等资源由于项目环境问题反而有可能会造成乱码。

拦截登陆

在访问特定uri时,先检测session中是否存在对应的字段

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/admin/*")
public class AdminFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
//禁止未登录的admin
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (request.getSession().getAttribute("admin")==null){
            response.setCharacterEncoding("utf-8");
            String s = "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>未登录</title>";
            s+="<script>function countDown(){var time=document.getElementById('Time');";
            s+="if(time.innerHTML==0){window.location.href='"+request.getContextPath()+"/index.html'}";
            s+="else{time.innerHTML=time.innerHTML-1}}window.setInterval('countDown()',1000);</script>";
            s+="<style>p{font-size:50px;text-align:center}#Time{font-size:100px;text-align:center}</style></head>";
            s+="<body><p>admin,您还未登录!</p><p>即将在3秒后自动跳转登录界面,点击<a href='"+request.getContextPath()+"/index.html'>";
            s+="立刻跳转</a></p><p id='Time'>3</p></body></html>";
            response.getWriter().println(s);
        }else{
            filterChain.doFilter(request,response);
        }
    }

    @Override
    public void destroy() {

    }
}

以上只是一个简单的示例且并不灵活,更灵活的方式是把拦截页面设置为Html静态文件,使用I/O流读取。

本篇完,还有疑问?留下评论吧

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注