Filter过滤器~~~编码过滤和登陆验证



Filter过滤器··简介:

  • Filter过滤器是一个小型的web组件(web三大组件之一), 可以动态地拦截url请求和响应, 以便查看、提取或操作包含在url请求和响应中的信息。


Filter过滤器的执行流程:
cd4356

  • 客户端发送请求后, Filter过滤器调用过滤器的doFilter方法对请求做预处理

  • 预处理完成之后, 请求会传递到servlet.service()方法进行正式处理, 并产生处理结果

  • 紧接着, Filter过滤器会拦截响应结果, 并调用doFilter方法对响应结果做后处理

  • 然后, 将响应结果返回给客户端


javax.servlet.Filter接口

自定义过滤器, 需要实现javax.servlet.Filter接口, 下面是Filter接口的源码:

package javax.servlet;

import java.io.IOException;

public interface Filter {

    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

  • 1、init()方法, 的形参是一个FilterConfig接口对象, 可以调用FilterConfig对象中的方法来获取过滤器的初始化参数、过滤器名称等操作. . .

    • init()方法会在web服务器启动创建过滤器对象时被调用, 并且只会执行一次。
    package javax.servlet;
    
    import java.util.Enumeration;
    
    public interface FilterConfig {
    
        String getFilterName();
    
        ServletContext getServletContext();
    
        String getInitParameter(String var1);
    
        Enumeration<String> getInitParameterNames();
    }
    

  • 2、doFilter()方法, 该方法中有三个参数:servletRequest、servletResponse 和 FilterChain。
    • servletRequest、servletResponse用于对请求和响应进行处理。

    • filterChain是一个接口对象, filterChain对象中提供了一个doFilter()方法, 当我们调用filterChain对象的doFilter()方法后,就会将请求转发给过滤器链的下一个过滤器, 当最后一个过滤器调用filterChain对象的doFilter()方法后, 就会将请求转发给Servlet, web服务器就会调用Servlet的service()方法, 这样就可以访问到拦截过滤的web资源了, 否则拦截的web资源不会被访问。

    • 每一次执行过滤器都会调用doFilter方法。


  • 3、destroy()方法, 会在web服务器关闭 或 重启时调用, 销毁过滤器对象。



应用场景:

场景一

  • 问题:表单提交时, 如果使用的是post方式提交数据, 提交的数据中如果含有中文汉字, 那么就会出现中文乱码问题。

  • 解决1:Servlet接受到请求后, 先通过request.setCharacterEncoding(“utf-8”);来设置请求的编码字符集, 然后再通过request.getParameter(“xxx”);来获取请求中的参数, 这样获取到的url参数就不会出现中文乱码问题。但这种方式需要在每个Servlet中都加上request.setCharacterEncoding(“utf-8”); 导致代码重复,且不利于后期维护。

  • 解决2:把设置请求和响应编码字符集的代码抽取出来, 放置到自定义过滤器中, 然后配置拦截所有请求, 把拦截的所有请求的编码字符集都设置为utf-8。


场景二

  • 问题:我们在访问一个网站的某个界面时, 可以在浏览器地址栏中输入相应地址, 就可以直接访问到所需页面。这样导致我们可以将数据库修改的一塌糊涂。

  • 解决:设置登陆权限验证, 在访问网站的一些隐私界面时, 需要先进行登陆。如果未登陆就直接访问隐私界面, 就会进行拦截, 然后将其重定向回登陆界面。但有一些请求是不需要拦截的, 比如去登陆的请求、登陆的请求等. . .



cd4356

创建一个form表单, 以post请求提交数据, 验证中文乱码现象

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <meta charset="UTF-8">
  <title>home</title>
</head>
<body>
<div class="main">
  <p>字符串拼接器</p>
  <form action="/encodingServlet" method="post">
    <p><input type="text" name="string1" placeholder="字符串1:"></p>
    <p><input type="text" name="string2" placeholder="字符串2: "></p>
    <input type="submit" value="提交">
  </form>
</div>
</body>
</html>

创建一个servlet, 对请求进行逻辑处理。

package com.cd4356;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = "/encodingServlet",loadOnStartup = 1)
public class EncodingServlet extends HttpServlet {

    public EncodingServlet() {
        System.out.println("正在创建FirstServlet对象");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("正在初始化FirstServlet对象");
    }

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        System.out.println("正在执行FirstServlet服务");
        String str1=request.getParameter("string1");
        String str2=request.getParameter("string2");
        String str = str1+str2;
        PrintWriter out = response.getWriter();
        out.println("<h2>");
        out.println("拼接结果为: "+str);
        out.println("</h2>");
    }

    @Override
    public void destroy() {
        System.out.println("正在销毁FirstServlet对象");
    }

}


使用post方式提交数据, 且提交的数据中含有中文, 所以出现了中文乱码问题。
cd4356


解决方法一: Servlet接受到请求后, 先通过request.setCharacterEncoding(“utf-8”);来设置请求的编码字符集为utf-8, 再获取请求中的参数, 这样就可以解决中文乱码问题了。

【缺点】: 需要在每个Servlet中都加上request.setCharacterEncoding(“utf-8”); 导致代码重复,且不利于后期维护。

package com.cd4356;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = "/encodingServlet",loadOnStartup = 1)
public class EncodingServlet extends HttpServlet {

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        //设置请求和响应的编码字符集
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        
        String str1=request.getParameter("string1");
        String str2=request.getParameter("string2");
        String str = str1+str2;
        PrintWriter out = response.getWriter();
        out.println("<h2>");
        out.println("拼接结果为: "+str);
        out.println("</h2>");
    }
}

cd4356


解决方法二

1、自定义一个EncodingFilter编码过滤器来实现Filter接口(注意:该Filter接口位于javax.servlet包下), 并重写init()doFilter()destory()。将设置请求和响应编码字符集这部分抽取出来, 放到自定义编码过滤器的doFilter方法中。

package com.cd4356;

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

public class EncodingFilter implements Filter {

    private String encoding;

    @Override
    public void init(FilterConfig config) throws ServletException {
        if(config.getInitParameter("encoding").equals("utf-8")){
            encoding  =config.getInitParameter("encoding");
        }
        encoding="utf-8";
    }

    //过滤器的关键方法,完成过滤器的功能(对请求进行预处理和对响应结果后处理)
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        chain.doFilter(request,response);
    }

    //用来定义过滤器销毁时做的一些操作
    @Override
    public void destroy() {

    }
}


2、定义了编码过滤器后, 还是无法使用的, 还需要我们到web.xml中对过滤器注册声明, 并映射到指定的url中。然后web服务器就会根据web.xml文件中的配置信息来创建每个注册的Filter过滤器对象, 并保存在服务器内存中。

<?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_4_0.xsd"
         version="4.0">

    <!--编码过滤器,处理中文乱码 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>com.cd4356.EncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <!--使用/*通配符,拦截所有资源请求,包括图片、等静态资源的请求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
</web-app>



cd4356
要求

1、设置请求和响应的编码字符集, 防止中文乱码。

2、用户输入账号密码 ----> 验证(判断用户是否存在) ----> 验证失败(账号密码错误),则重定向回登陆页面。

3、用户在地址栏中输入具体请求 ----> 拦截请求 ----> 判断用户是否登陆(session中是否存在用户信息) ----> 已登录,则放行 / 未登录,则拦截并重定向回登陆页面。


【登陆页面】login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <style>
        .main{
            width: 300px;
            text-align: center;
            padding: 20px;
            margin-top: 30px;
            margin-left: 30px;
            box-shadow: 0 0 5px 5px #ccc;
        }
    </style>
</head>
<body>
<div class="main">
    <p>登陆</p>
    <form action="/loginServlet" method="post">
        <p><input type="text" name="account" placeholder="账号:"></p>
        <p><input type="text" name="password" placeholder="密码: "></p>
        <input type="submit" value="提交">
    </form>
</div>
</body>
</html>

【主页面】home.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>home</title>
</head>
<body>
    <h3>欢迎你,来到xxx主页面!</h3>
</body>
</html>

【 User实体类, 保存登陆用户信息】

package com.cd4356;

public class User {
    private String account;
    private String password;

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

【登陆验证】

package com.cd4356;

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

@WebServlet(urlPatterns = "/loginServlet",loadOnStartup = 1)
public class LoginServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        super.init();
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取url中的account和password参数
        String account = request.getParameter("account");
        String password = request.getParameter("password");
        if (account.equals("aaa") && password.equals("bbb")){
            //将获取到的参数封装到user对象中
            User user = new User();
            user.setAccount(account);
            user.setPassword(password);
            //将user对象存到session中
            request.getSession().setAttribute("user",user);
            //重定向到home.html页面
            response.sendRedirect(request.getContextPath()+"/home.jsp");
            return;
        }
        response.sendRedirect(request.getContextPath()+"/login.jsp");
        return;
    }

    @Override
    public void destroy() {
        super.destroy();
    }
}

【编码过滤】

package com.cd4356;

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

public class EncodingFilter implements Filter {

    private String encoding;

    @Override
    public void init(FilterConfig config) throws ServletException {
        if(config.getInitParameter("encoding").equals("utf-8")){
            encoding =config.getInitParameter("encoding");
        }
        encoding="utf-8";
    }

    //过滤器的关键方法,完成过滤器的功能(对请求进行预处理和对响应结果后处理)
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        chain.doFilter(request,response);
    }

    //用来定义过滤器销毁时做的一些操作
    @Override
    public void destroy() {

    }
}

【登陆过滤】

package com.cd4356;

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

public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String url = request.getRequestURI();
        if (url.toLowerCase().indexOf("login")>=0){
            filterChain.doFilter(request,response);
            return;
        }

        //从session中获取登陆用户信息
        User user = (User) request.getSession().getAttribute("user");
        //用户未登陆,则重定向回登陆界面
        if(user==null){
            response.sendRedirect(request.getContextPath()+"/login.jsp");
            return;
        }
        //已登录,则继续执行过滤器链的下一个组件(下一个过滤器)
        filterChain.doFilter(request,response);
        return;
    }

    @Override
    public void destroy() {

    }
}

【注册过滤器】web.xml

<?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_4_0.xsd"
         version="4.0">

    <!--编码过滤器,处理中文乱码 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>com.cd4356.EncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>

    <filter>
        <filter-name>loginFilter</filter-name>
        <filter-class>com.cd4356.LoginFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <!--使用/*通配符,拦截所有资源请求,包括图片、等静态资源的请求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>loginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

cd4356



cd4356

1、在web应用程序中, 可以不配置过滤器、可以配置多个过滤器、也可以配置多个过滤器。如果配置了多个过滤器, 则这些过滤器就会相连以链的形式执行

在这里插入图片描述


2、过滤器链中, 过滤器的执行顺序与web.xml中<filter-mapping>的声明顺序有关(与<filter>无关), 遵从先声明、先执行的规则。

以场景2案例为例, EncodingFilter过滤器的<filter-mapping>先声明, 所以先执行EncodingFilter过滤器, 后执行LoginFilter过滤器。

如果想要反转过滤器的执行顺序, 只需在web.xml中反转<filter-mapping>的声明顺序即可。其实, 如果定义的Filter过滤器之间没有关联,那么, 我们就无需关心Filter过滤器的执行顺序。



Filter过滤器执行顺序总结:

  • 1、基于web.xml配置, 则过滤器执行顺序与<filter-mapping>相关, 遵从先声明、先执行的规则。

  • 2、基于注解配置, 则过滤器执行顺序与过滤器名称首字母顺序有关, 比如encodingFilter 和 loginFilter, e在l前面, 所以EncodingFilter过滤器先执行

    @WebFilter(filterName = "loginFilter",urlPatterns = "/*")
    public class LoginFilter implements Filter {
    	//write your code
    }
    
    @WebFilter(filterName = "encodingFilter",
        initParams = {
        @WebInitParam(name = "encoding",value = "utf-8")
        },
        urlPatterns = "/*")
    public class LoginFilter implements Filter {
    	//write your code
    }
    
  • 3、如果部分过滤器基于web.xml配置, 另一部分基于注解配置。则基于web.xml配置的过滤器先执行




cd4356

Spring MVC框架给我们提供了一个CharacterEncodingFilter编码过滤器,我们在开发Spring MVC项目过程中,可以自定义编码过滤器,也可以使用Spring MVC提供的CharacterEncodingFilter编码过滤器

那么,自定义编码过滤器 和 CharacterEncodingFilter编码过滤器有什么区别呢?

  • 其实它们的功能都是一样, 但使用CharacterEncodingFilter编码过滤器可以省略自定义编码过滤器这一步, 我们直接在web.xml文件中注册使用即可, 在一定程度上简化了我们的开发。
<?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_4_0.xsd"
         version="4.0">

 	<!--注册CharacterEncodingFilter过滤器-->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <!--指定过滤器的类(全类名),web服务器才会对该过滤器类进行对象的创建-->
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!--过滤器参数初始化-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <!--使用/*通配符,拦截所有请求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
	
</web-app>



Filter过滤器案例源码


扩展:
web三大组件
web三大组件

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

家师曹先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值