Servlet 过滤器

Posted 伍有晓俐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet 过滤器相关的知识,希望对你有一定的参考价值。


恰同学少年,风华正茂;书生意气,挥斥方遒。—《沁园春·长沙》


1 过滤器的定义

过滤器是一个服务器端的组件,它主要用于客户端(浏览器)的请求进行过滤处理,再将过滤后的请求转发到下一资源,他在 JSP网站开发中具有非常重要的作用。

过滤器实质就是在 Web 应用服务器上的一个 Web 应用组件,用于拦截客户端(浏览器)对目标资源的请求,并对这些请求进行处理再发给目标资源。

过滤器拦截请求,不是禁止访问,相应处理后,还会转到目标地址
所拦截的请求路径可以是 servlet 或者是某个页面路径 /index.jsp等
过滤器拦截servlet或者jsp页面内容,比如内容替换,再向用户展现修改后的页面

过滤源—>过滤规则—->过滤结果

观看一个视频网站时,对于同一个网页地址,登录过的用户,直接能观看,未登录的用户,则跳转到登录界面

访问一个页面时,该页面无法加载或不存在,可以过滤请求,返回一个错误页

2 过滤器的工作原理

没有过滤器,用户直接访问资源。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

3 过滤器两种配置方法

过滤器和Servlet 十分类似,都需要进行配置,在 Servlet3.0 中,提供了采用注解的方式配置过滤器,如:

@WebFilter(filterName="FirstFilter",
urlPatterns="/*",
initParams={
        @WebInitParam(name="mood",value="awake")})

urlPatterns 属性:用于指定那些 URL 应用该过滤器。如果指定所有页面均应用该过滤器可以设置为“/*”。
initParams 属性 用于指定初始化参数

在web.xml 文件中配置

 <filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>filter.FirstFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
<filter>指定一个过滤器。
    <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
    <filter-class>元素用于指定过滤器的完整的限定类名。
    <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。
    在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。

<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
    <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
    <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)


FirstFilter.java

//package filetr;

import java.io.IOException;
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.annotation.WebFilter;

/**
 * Servlet Filter implementation class FirstFilter
 */
@WebFilter("/*")// 采用注解的方式
public class FirstFilter implements Filter {

    /**
     * Default constructor. 
     */
    public FirstFilter() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        // TODO Auto-generated method stub
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        // place your code here

        // pass the request along the filter chain
        chain.doFilter(request, response);
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        // TODO Auto-generated method stub
    }
}

init() 过滤器的初始化方法,Web容器创建过滤器实例后将调用这个方法,这个方法可以获取web.xml文件中的过滤器参数。

doFilter() 完成实际的过滤操作。过滤器的核心方法,当用户请求访问与过滤器关联的URL时,Web容器将先调用过滤器的doFilter方法。 FilterChain参数可以调用chain.doFilter方法,将请求传给下一个过滤器(或目标资源),或利用转发、重定向将请求转发到其他资源。

destroy() Web容器在销毁过滤器实例前调用该方法,可以释放过滤器占用的资源。(大多数情况下用不到)

4 过滤器示例

FilterConfig 使用

Filter 的 init 方法中提供了一个 FilterConfig 对象。

如 web.xml 文件配置如下:

<filter>
    <filter-name>LoginFilter</filter-name>
    <filter-class>com.runoob.test.LogFilter</filter-class>
    <init-param>
        <param-name>Site</param-name>
        <param-value>菜鸟教程</param-value>
    </init-param>
    </filter>

在 init 方法使用 FilterConfig 对象获取参数:

public void  init(FilterConfig config) throws ServletException {
    // 获取初始化参数
    String site = config.getInitParameter("Site"); 
    // 输出初始化参数
    System.out.println("网站名称: " + site); 
}

示例

利用过滤器,实现网站访问计数器的功能,并在配置过滤器时,将网站访问的初始值设置为 1000.

每一次访问页面,都会通过过滤器,过滤器里使count 值每次 加一,达到计数器的效果。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主界面</title>
</head>
<body>
    <h2>
    欢迎光临,<br>
    您是本站的第【 
    <%=application.getAttribute("count") %>
     】位访客!
     </h2>
</body>
</html>

CountFilter.java

//package com.mingrisoft;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;

/**
 * Servlet过滤器实现类CountFilter
 */
@WebFilter(urlPatterns = { "/index.jsp" }, initParams = { @WebInitParam(name = "count", value = "1000") })
public class CountFilter implements Filter {
    private int count; // 来访数量

    /**
     * 默认构造方法
     */
    public CountFilter() {
        System.out.println("CountFilter的构造方法 ....");
    }

    /**
     * 销毁方法
     */
    public void destroy() {
        System.out.println("CountFilter的destroy ....");
    }

    /**
     * 过滤处理方法
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        count++; // 访问数量自增
        // 将ServletRequest转换成HttpServletRequest
        HttpServletRequest req = (HttpServletRequest) request;
        // 获取ServletContext
        ServletContext context = req.getServletContext();
        context.setAttribute("count", count); // 将来访数量值放入到ServletContext中
        System.out.println("CountFilter的start ....");
        chain.doFilter(request, response); // 向下传递过滤器
        System.out.println("CountFilter的end ....");
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        System.out.println("CountFilter的init ....");
        String param = fConfig.getInitParameter("count"); // 获取初始化参数
        count = Integer.valueOf(param); // 将字符串转换为int
    }

}
第一次启动index.jsp
CountFilter的构造方法 ....
CountFilter的init ....
CountFilter的start ....
CountFilter的end ....

刷新一次index.jsp页面,执行一次doFilter()
CountFilter的start ....
CountFilter的end ....

5 Servlet 监听器

Servlet 监听器可以监听到 在特定事件发生的事件,并根据其做出相应的反应。

监听器的作用是监听 Web 容器的有效期事件,因此它是由容器管理的。利用 Listener 接口监听在容器中的某个执行程序,并且根据应用程序的需求做出适当的响应。

下表列出了 Servlet 和 JSP中的 8 个Listener 和 6 个Event 类。

Listener接口Event类
ServletContextListenerServletContextEvent
ServletContextAttributeListenerServletContextAttribute
HttpSessionListener / HttpSessionActivationListenerHttpSessionEvent
HttpSessionAttributeListener / HttpSessionBindingListenerHttpSessionBindingEvent
ServletRequestListenerServletRequestEvent
ServletRequestAttributeListenerServletRequestAttributeEvent

Servlet 上下文监听

Servlet 上下文监听可以监听 ServletContext 对象的创建、删除、属性的添加、删除和修改操作,该监听器需要用到一下两个接口。
1.ServletContextListener 接口

它主要实现监听 ServletContext 的创建和删除。

2.ServletAttributeListener 接口

它主要实现监听 ServletContext 属性的增加、删除、修改操作。

示例

创建并配置上下文监听器,实现当项目发布时,在控制台输出提示信息“初始化”;当项目被移去时,在控制台输出文字“销毁”。
FirstListener.java

//package com.mingrisoft;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;


@WebListener        //配置监听器
public class FirstListener implements ServletContextListener {

    /**
     * 默认构造方法 
     */
    public FirstListener() {
    }

    /**
     * Servlet上下文初始化成功时触发的方法
     */
    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("初始化");
    }

    /**
     * Servlet上下文被销毁时触发的方法
     */
    public void contextDestroyed(ServletContextEvent arg0) {
        System.out.println("销毁");
    }
}

6 综合实例-编写一个字符编码过滤器

其实就是把这两句封装在过滤器中,让它可以重用。

request.setCharacterEncoding("UTF-8"); // 设置request的编码格式                        response.setContentType("text/html; charset=UTF-8");// 设置response字符编码

CharactorFilter.java

//package com.mingrisoft;

import java.io.IOException;
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.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

/**
 * Servlet过滤器实现类CharactorFilter
 */
@WebFilter(urlPatterns = { "/*" }, initParams = { @WebInitParam(name = "encoding", value = "UTF-8") }) // 配置过滤器
public class CharactorFilter implements Filter {
    String encoding = null; // 字符编码

    public CharactorFilter() {
    }

    /**
     * 销毁方法
     */
    public void destroy() {
        encoding = null;
    }

    /**
     * 过滤处理方法
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (encoding != null) { // 判断字符编码是否为空
            request.setCharacterEncoding(encoding); // 设置request的编码格式 //
            response.setContentType("text/html; charset=" + encoding);// 设置response字符编码
        }
        chain.doFilter(request, response); // 传递给下一过滤器
    }

    /**
     * 初始化方法
     */
    public void init(FilterConfig fConfig) throws ServletException {
        encoding = fConfig.getInitParameter("encoding"); // 获取初始化参数
    }

}

AddServlet .java

//package com.mingrisoft;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class AddServlet
 */
@WebServlet("/AddServlet")
public class AddServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public AddServlet() {
        super();
    }

    /**
     * 处理GET请求的方法
     */
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);// 处理GET请求
    }

    /**
     * 处理POST请求的方法
     */
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 处理POST请求
        PrintWriter out = response.getWriter(); // 获取 PrintWriter
        String id = request.getParameter("id"); // 获取图书编号
        String name = request.getParameter("name"); // 获取名称
        String author = request.getParameter("author"); // 获取作者
        String price = request.getParameter("price"); // 获取价格
        out.print("<h2>图书信息添加成功</h2><hr>"); // 输出图书信息
        out.print("图书编号:" + id + "<br>");
        out.print("图书名称:" + name + "<br>");
        out.print("作者:" + author + "<br>");
        out.print("价格:" + price + "<br>");
        out.flush(); // 刷新流
        out.close(); // 关闭流
    }
}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加图书信息</title>
<style type="text/css">
ul {
    list-style: none;
}
li{padding:5px;}

</style>
</head>
<body>
    <section>
        <h2>   添加图书信息</h2>
        <form action="AddServlet" method="post">
            <ul>
                <li>图书编号:<input type="text" name="id"></li>
                <li>图书名称:<input type="text" name="name"></li>
                <li>作  者:<input type="text" name="author"></li>
                <li>价  格:<input type="text" name="price"></li>
                <li>     <input type="submit" value="添 加"></li>
            </ul>
        </form>
    </section>
</body>
</html>

这里写图片描述

以上是关于Servlet 过滤器的主要内容,如果未能解决你的问题,请参考以下文章

是否可以编写一个 servlet 过滤器来检查 HTTP 响应代码? [复制]

Servlet过滤器行为模棱两可?

servlet 过滤器(Filter)

javaweb-Servlet过滤器Filter

为什么我不能在此片段中生成唯一对象数组?

servlet 过滤器中的 StringBuffer 与 StringBuilder