话说:
Servlet之后,我们客串了一下数据连接池,这会总结一下过滤器——Filter。
What?
Flilter即过滤器,就是javax.servlet包下面的一个接口。实现这个接口可以帮我们做很多事情。它是向Web应用程序的请求和响应添加功能的Web服务组件;可以统一的集中处理请求和响应;实现对数据的过滤。
可是还是抽象,到底有什么卵用?
应用场合:
1、对请求和响应进行统一处理
2、对请求日志进行日志记录和审核
3、对数据进行屏蔽和替换
笔者猜测,屏蔽色情、论坛屏蔽敏感字段可能会用到这个
4、对数据进行加密和解密
近代的电报,和这个类似吧
Why?
貌似跟我们有毛线关系啊?有的。还记得前面,我们写了很多个Servlet,后来简化成了BaseServlet,在BaseServlet里面,写多个方法。方法里面实现调用。本质还是一个Servlet处理一个请求。然鹅,Filter就可以实现一个Filter处理按照正则表达式匹配后满足条件的所有请求。这里我们来3个案例,实践出真知嘛!
案例一:MyFilter(Filter的实现及生命周期)
案例二:Filter实现权限过滤
案例三:Filter字符编码过滤
案例一:MyFilter(Filter的实现及生命周期)
Filter是什么东东?如何用呢?建立一个Filter步骤:
1)建立实现Filter接口的类(javax.servlet.Filter)也就是Tomcat自带的lib
2)实现过滤行为
3)在web.xml中配置过滤器
1)建立实现Filter接口的类(javax.servlet.Filter)也就是Tomcat自带的lib
整体工程架构图如下:
MyFilter
package com.hmc.filter;
import javax.servlet.*;
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 java.io.IOException;
/**
* User:Meice
* 2017/10/6
*/
public class MyFilter implements Filter{
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println("Filter初始化....");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
System.out.println("请求来了...");
//执行过滤
chain.doFilter(req,resp);
System.out.println("处理响应...");
}
@Override
public void destroy() {
System.out.println("Filter销毁啦....");
}
}
需要注意的是,一定要调用doFilter(request,response)方法,且在这个方法之前是过滤请求,此方法之后,过滤响应。那么以后如果写关于请求的操作,就要在该方法之后。
配置web.xml
<!--配置MyFilter过滤器-->
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.hmc.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<!-- <url-pattern>/*</url-pattern>--><!--对所有请求过滤;一般我们不同时写多个过滤条件-->
<!-- <url-pattern>/admin/*</url-pattern>--><!-- 对admin目录下的所有请求进行过滤-->
<url-pattern>*.do</url-pattern><!--对所有以.do结尾的请求过滤-->
</filter-mapping>
这里,我们开启猫,然后做各种测试即可。
总结:
1、Filter根据你的条件,对所有符合条件的请求进行过滤;如果是目录的话,目录下的任何请求也照样过滤;
2、对比Servlet,当年我们写Servlet的时候,每写一个Servlet都要处理编码,每一个请求最开始也要写对应的Servlet,好在后面我们用BaseServlet进行了优化。
4、Filter的生命周期和Servlet一模一样,不过Filter在一开始启动猫的时候就初始化了,然后执行请求,最后销毁。从此,我们又可以掌控Filter的生命啦,有木有感觉很有权力感?
*案例二:Filter实现权限过滤*
我们在web根目录下创建一个admin的目录,该目录下新建一个manager.jsp;代表后台管理界面。
按照案例一的过滤方法,如果我们知道这个目录,就可以直接访问的admin下的任何一个页面,这有点可怕。后台页面只允许管理员才能访问的,这就是案例二要解决的问题:如何通过过滤器来管理权限?
思路是这样的,我们把问题简化一下,如果在登录界面,用户没有输入用户名和密码,我们直接提示用户“未登录”,并且页面跳转到login.jsp;如果用户输入了用户名和密码,判断用户名是否等于admin,如果相等,ok,才允许跳转到admin目录下的manager.jsp页面(执行管理员操作);如果用户名不等于admin,跳转到noaccess.jsp页面,并给出权限不足提示。
页面整体架构图见案例一那张图。
1)用户在登录界面一旦登录,我们通过LoginSerlvet在后台获取用户名和密码,存到session里面,这里不做页面跳转。
登陆页面代码login.jsp
<%--
User: Meice
Date: 2017/10/6
Time: 18:41
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登陆</title>
</head>
<body>
<form action="login.do" method="post">
用户名:<input type="text" name="uname"><br/>
密码:<input type="password" name="pwd"><br/>
<input type="submit" value="登陆">
</form>
</body>
</html>
编写LoginServlet
package com.hmc.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* User:Meice
* 2017/10/6
*/
public class LoginServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接受参数
String uname = req.getParameter("uname");
String pwd = req.getParameter("pwd");
//存储session
req.getSession().setAttribute("curUser",uname);
}
}
在web.xml中配置LoginServlet
<!--Login Servlet 配置-->
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.hmc.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
这样,一旦用户登陆,我们就把页面的参数存在了session里,便于下一步的权限判断。
2)用户一旦你在地址栏输入localhost://8080/JavaWeb_Filter/admin/manager.jsp;也就是用户企图访问后台管理员界面的时候,我们设置一个过滤器AuthFilter来做权限判断。
编写AuthFilter
package com.hmc.filter;
import javax.servlet.*;
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.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* User:Meice
* 2017/10/6
*/
public class AuthFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
chain.doFilter(req,resp);
//转换一下请求
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//设置编码;奇怪的是,未设置编码也没出现乱码啊!server.xml也没有改
// request.setCharacterEncoding("utf-8");
// response.setCharacterEncoding("utf-8");
//判断sessiion是否为空
String uname =(String) request.getSession().getAttribute("curUser");
System.out.println("uname:"+uname);
//如果不输入用户名,默认是"",而不是null值,以下是验证
/* System.out.println("uname == null?"+uname==null);
System.out.println("uname== \"\" "+"".equals(uname));*/
//以下验证路径问题(相对路径、绝对路径)
System.out.println("=====================================");
System.out.println("我是Scheme: "+request.getScheme());
System.out.println("我是ServerName :"+request.getServerName());
System.out.println("我是ServerPort:"+request.getServerPort());
System.out.println("我是ContextPath: "+request.getContextPath());
//所以把我们拼接在一起就是这样
System.out.println(request.getScheme()+"://"+request.getServerName()+":"+
request.getServerPort()+request.getContextPath()+"/"
);
//需要注意ContextPath自动带上半边/;为避免路径过长,一般我们这么写:
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
/**
* 页面获取路径用
* <%>=basePath</%>或者${basePath}即可;ContextPath就是项目路径
*/
//获取上下文路径
String root = request.getContextPath();
if(uname !=null && !"".equals(uname)){
//判断session用户是否是管理员
if("admin".equals(uname)){
}else{
response.getWriter().write("<script>alert('权限不足');location.href='"+root+"/noaccess.jsp'</script>");
}
}else{
response.getWriter().write("<script>alert('尚未登录');location.href='"+root+"/login.jsp'</script> ");
}
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
这里需要注意一下路径的问题,上面root的作用就在此。为此,上面代码中间加入了以下这部分,仅仅作为路径的验证,读者可以忽略。
//以下验证路径问题(相对路径、绝对路径)
System.out.println("=====================================");
System.out.println("我是Scheme: "+request.getScheme());
System.out.println("我是ServerName :"+request.getServerName());
System.out.println("我是ServerPort:"+request.getServerPort());
System.out.println("我是ContextPath: "+request.getContextPath());
//所以把我们拼接在一起就是这样
System.out.println(request.getScheme()+"://"+request.getServerName()+":"+
request.getServerPort()+request.getContextPath()+"/"
);
//需要注意ContextPath自动带上半边/;为避免路径过长,一般我们这么写:
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
/**
* 页面获取路径用
* <%>=basePath</%>或者${basePath}即可;ContextPath就是项目路径
*/
同样,配置Web.xml中的过滤器
<!--配置权限过滤器-->
<filter>
<filter-name>authFilter</filter-name>
<filter-class>com.hmc.filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>authFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
这样用户访问的时候,如果没有填写用户名或者密码,就跳转到login.jsp;如果已经填写,不是admin,那么就会跳转到noaccess.jsp
noaccess.jsp代码如下:
<%--
User: Meice
Date: 2017/10/7
Time: 8:03
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>管理权限</title>
</head>
<body>
<h2>您没有访问权限,请联系管理员授权!</h2>
</body>
</html>
好了,到此为止,我们就实现了对后台权限页面的全面掌控!
案例三:Filter字符编码过滤
目的:我们希望,对web根目录下的所有请求在初始化的时候就处理掉编码,而不用每次在对应的Filter的doFilter()里面重复类似的代码
request.setCharacterEncoding(“utf-8”);
response.setCharacterEncoding(“utf-8”);
那么如何设置初始化参数呢?
跟Servlet一模一样,我们新建一个Filter叫做EncodingFilter专门处理字符编码,具体结构请参考上一张架构图。
EncodingFilter代码如下:
package com.hmc.filter;
import javax.servlet.*;
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.io.IOException;
/**
* User:Meice
* 2017/10/7
*/
public class EncodingFilter implements Filter {
String encoding = null;
@Override
public void init(FilterConfig config) throws ServletException {
//初始化的时候就获取编码
encoding = config.getInitParameter("encoding");
//验证是否得到参数
System.out.println("初始化编码:"+encoding);
//判断字符编码值是否为空
if(encoding == null || "".equals(encoding)){
encoding="UTF-8";
}
System.out.println("初始化编码:"+encoding);
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
//这里用到了向下转型,主要还是方便session的获取,因为session属于HttpSession
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
//上面转换过来了,过滤当然也要过滤转化后的request,response
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
web.xml配置如下:
<!--配置字符编码过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.hmc.filter.EncodingFilter</filter-class>
<!--配置初始化参数encoding-->
<init-param>
<param-name>encoding</param-name>
<param-value></param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern><!--字符编码,当然要对所有请求处理啦-->
</filter-mapping>
配置Filter的初始化参数和Servlet一模一样奥。如果读者对于Servlet不熟悉,请回看笔者关于Servlet相关的所有博客。哈哈。
到这里,我们的字符编码处理好啦!不论你是否给了字符编码的初始化参数,我们都设置为了再也亲切不过的UTF-8了。web目录下的所有请求都会经过这个字符编码过滤器!宝宝再也不用担心中文乱码的的问题啦!
还需要注意一下,我们到此为止,3个案例全部结束,整体的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_3_1.xsd"
version="3.1">
<!--配置MyFilter过滤器-->
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.hmc.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<!-- <url-pattern>/*</url-pattern>--><!--对所有请求过滤;一般我们不同时写多个过滤条件-->
<!-- <url-pattern>/admin/*</url-pattern>--><!-- 对admin目录下的所有请求进行过滤-->
<url-pattern>*.do</url-pattern><!--对所有以.do结尾的请求过滤-->
</filter-mapping>
<!--Login Servlet 配置-->
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.hmc.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
<!--配置权限过滤器-->
<filter>
<filter-name>authFilter</filter-name>
<filter-class>com.hmc.filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>authFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
<!--配置字符编码过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.hmc.filter.EncodingFilter</filter-class>
<!--配置初始化参数encoding-->
<init-param>
<param-name>encoding</param-name>
<param-value></param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern><!--字符编码,当然要对所有请求处理啦-->
</filter-mapping>
</web-app>
以上总共有有3个过滤器:形成了一个过滤器链;这么多过滤器,那么执行顺序呢?所以,过滤器链按找注册先后顺序执行,也就是配置位置的先后顺序。
所以,字符编码应该放在权限配置之前奥。
Ok!睡个午觉吧。
2222

被折叠的 条评论
为什么被折叠?



