您的位置:首页 > 编程语言 > Java开发

Day5-----Java之神秘的过滤器

2020-03-06 17:17 681 查看
什么是过滤器
Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
  Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。
2.2 如何编写过滤器
1、编写java类实现Filter接口
2、重写doFilter方法
3、设置拦截的url

入门案例:

package com.qf.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
* @author wgy 2018/11/28 9:23
* @version 1.0
*/
@WebFilter("/myservlet1")//过滤路径
public class MyFilter1 implements Filter {

//初始化过滤器
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化了........init...  "+filterConfig);
}

//执行过滤
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("过滤前........doFilter ");
//放行
chain.doFilter(request, response);

System.out.println("过滤后.......doFilter");

}

//销毁
@Override
public void destroy() {
System.out.println("销毁了.....destroy");
}
}
2.3 过滤器的配置
2.3.1 注解式配置

在自定义的Filter类上使用注解@WebFilter(“/*”)

2.3.2 xml配置

在web.xml中进行过滤器的配置:

<!--过滤器的xml配置  -->
<filter>
<!--名称-->
<filter-name>sf</filter-name>
<!--过滤器类全称-->
<filter-class>com.qf.web.filter.SecondFilter</filter-class>
</filter>
<!--映射路径配置-->
<filter-mapping>
<!--名称-->
<filter-name>sf</filter-name>
<!--过滤的url匹配规则和Servlet的一模一样-->
<url-pattern>/*</url-pattern>
</filter-mapping>
2.4 过滤器链

(在资源放行前,过滤请求,在资源放行后,过滤响应,多个过滤器之间过滤成链)

通常客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。
每个过滤器实现某个特定的功能,一个过滤器检测多个Servlet。(匹配几个,检测几个)。
一组过滤器中的执行顺序与<filter-mapping>的配置顺序呢有关。
当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源
2.5 过滤器的优先级
在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter。当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源

如果为注解的话,是按照类名的字符串顺序进行起作用的
如果web.xml,按照 filter-mapping注册顺序,从上往下
web.xml配置高于注解方式
推荐使用xml方式进行配置
2.6 过滤器的初始化参数

在过滤器的创建的时候,可以传递初始化参数

第一种:基于注解的

/**
* Servlet Filter implementation class FirstFilter 创建过滤器
*/
@WebFilter(value="/*",initParams= {@WebInitParam(name = "version", value = "1.0")})
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
System.out.println("destroy销毁……");
}

/**
* @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
System.out.println("doFilter……过滤");
// 是否继续---访问下一个
chain.doFilter(request, response);
}

/**
* @see Filter#init(FilterConfig)
* 初始化
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("init……初始化");
System.out.println("初始化参数:版本号:"+fConfig.getInitParameter("version"));
}
}

第二种:基于xml配置

/**
*  创建过滤器
*/
public class SecondFilter implements Filter {

/**
* Default constructor.
*/
public SecondFilter() {
// 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 {
// 是否继续---访问下一个
chain.doFilter(request, response);
}

/**
* @see Filter#init(FilterConfig)
* 初始化
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("初始化参数:版本号:"+fConfig.getInitParameter("version"));
}

}

Web.xml实现配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>Web_Day</display-name>

<!--过滤器的xml配置  -->
<filter>
<filter-name>myfilter</filter-name>
<filter-class>com.qf.web.filter.SecondFilter</filter-class>
<!--过滤器的初始化参数  -->
<init-param>
<param-name>version</param-name>
<param-value>1.0</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
2.7 过滤器的优点

可以实现 Web 应用程序中的预处理和后期处理逻辑

chain.doFilter(req, resp);//资源放行
如果不去执行这一句话,那么请求就会被拦截,不再继续往下走
在资源放行的前后,我们可以对请求进行处理和对响应进行处理
2.8 过滤器的典型应用

过滤器的作用来看

1.过滤所有的请求,因为他是在servlet.jsp.html等资源执行之前执行,可以类似封装的作用,比如处理乱码
2.可以在资源放行之前,对request进行处理,过滤敏感词
3.我们可以在资源放行之后,对资源响应给浏览器的response进行相关处理:压缩响应内容
案例1禁用浏览器缓存

web对静态资源有缓存作用(img,html,js,css)

对于目前现在的浏览器,get请求动态资源缓存问题已经解决。

max-age<=0 时 向server 发送http 请求确认 ,该资源是否有修改

对于静态资源部分浏览器使用Cache-Control头和Expires头设置缓存时间。

对于静态资源服务器会采用304状态码控制是否再次发送数据,从而节省带宽;可以通过Cache-Control=no-store,Expires=-1,Pragma=no-cache控制304无效。

package com.qf.filter;

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

public class CacheFilter implements Filter {
public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将req转换成HttpServletRequest
HttpServletRequest request= (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) resp;
//通过以下参数的设置,可以禁用浏览器缓存
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-store");
response.setHeader("Pragma","no-cache");
chain.doFilter(req, resp);
}

public void init(FilterConfig config) throws ServletException {
//获取初始化参数
String driverClassName = config.getInitParameter("driverClassName");
System.out.println(driverClassName+"============================================");

}

}

作业:如何设置浏览器缓存时间

respose.setHeader(“Cache-control”,“max-age=600”);

response.setDateHeader(“Expires”,600000);

案例2 自动登录

注意:

1.不失页面拦截
2.权限相关的内容,没有从登录页面进到index页面是不允许的,如何解决
3.当用户访问login.jsp,被过滤器拦截,然后过滤器查看有没有session,有没有cookie,如果有,就不需要用户再次输入用户名和密码

if(session失效了){
if(cookie中的值是不是真的){
//直接进到主页面
}else{
资源放行,让他去login.jsp重新输入用户名和密码
}
}else{
//直接进到主页面
}
package com.qf.filter;

import com.qf.User;

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

public class LoginFilter implements Filter {
public void destroy() {
}
//过滤器过滤的只是login.jsp
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将req转换成HttpServletRequest
HttpServletRequest request= (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) resp;
//判断有没有登陆==》session中有没有user
//未来提升用户体验,我考虑了seesion失效,但是cookie还存在的情况
if(request.getSession().getAttribute("user")==null){
//我自己多干了一件事,我想在判断万一cookie中存了用户名和密码呢?
/*if(session失效了){
if(cookie中的值是不是真的){
//直接进到主页面
}else{
资源放行,让他去login.jsp重新输入用户名和密码
}
}else{
//直接进到主页面
}
*
*
*
*
*
*
*
* */

/*//万一遇到seeion过期,但是浏览器中还有cookie,如果用户在当前页面直接点击刷新,
//会被拦截所有的过滤器拦截(这个过滤器只是防止用户不经过登录直接进来,所以他只判断session)*/

Cookie[] cookies = request.getCookies();
User user=null;
if(cookies!=null){
//去拿那个叫userInfo的cookie
for(Cookie c:cookies){
if(c.getName().equals("userInfo")){
String[] ss = c.getValue().split("#");//admin#123456
user=new User(ss[0],ss[1]);
break;
}
}
}

//模拟一个登陆过程
//User u=UserService.login(username,password);
//cookie中拿到username和password之后,我们防止恶意存cookie,所以我们需要重新登陆

if("admin".equals(user.getUsername())&&"123456".equals(user.getPassword())){
request.getSession().setAttribute("user",user);
response.sendRedirect("aaa.html");
}else{
//登陆失败了,就开始资源放行,回到login.jsp,重新输入用户名和密码
chain.doFilter(request,response);
}
}else{
//就说明已经登陆过了,不需要资源放行,应该重定向到aaa.html
response.sendRedirect("aaa.html");
}

/*    chain.doFilter(req, resp);*/
}

public void init(FilterConfig config) throws ServletException {

}

}

package com.qf.controller;

import com.qf.User;

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

public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
//模拟一个登陆过程
//User u=UserService.login(username,password);
User user=null;
if("admin".equals(username)&&"123456".equals(password)){
user=new User(username,password);
}else{
response.getWriter().println("登陆失败");
return;//返回到方法的调用处
}

//将user对象保存在session域中
request.getSession().setAttribute("user",user);
//放到cookie中(以后不需要)userInfo:admin#123456
Cookie cookie=new Cookie("userInfo",username+"#"+password);
response.addCookie(cookie);
//登陆成功之后
response.sendRedirect("aaa.html");
}
}
案例3 过滤脏词
package com.qf.filter;

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

public class DirtyFilter implements Filter {
public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//是不是要在资源放行之前把request摁住检查一遍,如果出现铭感词,将敏感词替换掉,然后再将request资源放行
HttpServletRequest request= (HttpServletRequest) req;

//在资源放行之前对request请求做相关操作
//对request对象进行重新包装
chain.doFilter(new MyRequest(request), resp);
}

public void init(FilterConfig config) throws ServletException {

}

}

package com.qf.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

//ctrl+shift+alt+u
public class MyRequest extends HttpServletRequestWrapper {
List<String> list=new ArrayList<>();

public MyRequest(HttpServletRequest request) {
super(request);
list.add("sb");
list.add("111");

}

//重新定义getParmarter();
@Override
public String getParameter(String name) {
String aaa=super.getParameter(name);//获取原来要传过来的值
for(String s:list){
if (s.equals(aaa)) {

return "***";
}
}

return aaa;
}
}
案例4 过滤器解决编码
package com.qf.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

@WebFilter("/*")
public class SimpleFilter implements Filter {
public void destroy() {
}
//不需要在每一个servlet的方法中添加下面这个重复代码了
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charaset=utf-8");
chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {
}

}
案例五:对响应文本内容进行压缩
package com.qf.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

@WebFilter("/*")
public class GZipFilter implements Filter {
public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将response摁住,需要将PrintWriter的输出对象给换掉,由浏览器换成可压缩的缓冲区(内存输出流)
ByteArrayOutputStream oldBos=new ByteArrayOutputStream();//实例化了一个对象,内存流

chain.doFilter(req, new MyResponse((HttpServletResponse) resp,oldBos));
System.out.println("压缩前"+oldBos.size());//此时oldbos中已经有内容了

//对内存流进行压缩就行了
ByteArrayOutputStream newBos=new ByteArrayOutputStream();//实例化了一个对象,内存流
//压缩流
GZIPOutputStream gzip=new GZIPOutputStream(newBos);
gzip.write(oldBos.toByteArray());
gzip.flush();
gzip.close();
System.out.println("压缩后"+newBos.size());

//浏览器自带解压功能,只需要在响应头中告诉他这是压缩文件,他就会自动解压
HttpServletResponse response= (HttpServletResponse) resp;
response.setHeader("Content-Encoding","gzip");
response.getOutputStream().write(newBos.toByteArray());

}

public void init(FilterConfig config) throws ServletException {

}

}

package com.qf.filter;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
//HttpServletResponseWrapper这是一个包装类,必须要给一个response对他包装
public class MyResponse extends HttpServletResponseWrapper {
private PrintWriter pw;
private ByteArrayOutputStream bos;//缓冲区
public MyResponse(HttpServletResponse response,ByteArrayOutputStream bos) {
super(response);
this.bos=bos;
}

public MyResponse(HttpServletResponse response) {
super(response);

}

@Override
public PrintWriter getWriter() throws IOException {

System.out.println("你的方法被我重构了,pw是我自定义的pw");
pw=new PrintWriter(new OutputStreamWriter(bos,"utf-8"));

return pw;
}
}

package com.qf.controller;

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;
import java.io.PrintWriter;

public class GZipServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String a="11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
System.out.println("你要写到浏览器的内容大小为:"+a.getBytes().length);//245

PrintWriter pw = response.getWriter();
pw.println(a);
pw.flush();
}
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
java404fzf 发布了10 篇原创文章 · 获赞 0 · 访问量 78 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: