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(); } }
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- JavaWeb_day5-监听器和过滤器
- Java乔晓松-过滤器(自动登录)
- JAVA文件过滤器
- Java Web 过滤器简介
- Java 中的 Filter 过滤器详解
- java 过滤器filter使用案例
- java 拦截器、过滤器、监听器
- 使用java的自定义过滤器Filter 处理请求request 并响应response
- java基础----Java数据类型转换神秘面纱(3)
- Java基础day5(栈和堆,冒泡排序)
- Java中过滤器Filter的使用
- 拦截器和过滤器有什么区别(JAVA/struts2.0)
- Java Web开发中,自定义过滤器被执行两次的原因分析及解决办法
- javaWeb之过滤器
- java基础(二十九):过滤器
- java程序员第二十一课 -过滤器 Filter(重点)
- Java Web开发----过滤器
- java 过滤器
- java JFileChooser与 文件过滤器FileFilter
- Java 8新特性探究(三)解开lambda最强作用的神秘面纱