JavaWEB过滤器和监听器技术
Posted A小小高
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWEB过滤器和监听器技术相关的知识,希望对你有一定的参考价值。
-
过滤器介绍
-
什么是过滤器
-
生活中的例子:
滤水器,口罩,杯子上滤网,渔网
生活中的过滤器:留下我们想要的,排除,我们不想要的。
高考: 只有分数够高的同学才能进入理想的大学。有一部分同学被拦截在大学之外。(起到拦截的作用)
传智播客: 一开始大家都是小白,进入传智播客学习,经历了4个月的学习,毕业之后,具有了一定(月薪10000左右)的编码能力。
(对每一个经过的学员,都增强了学员的编码能力,起到了增强的作用)
JavaWeb中的过滤器的概念: 对请求和响应进行拦截或者增强的对象,就是过滤器。
JavaWeb中的过滤器是什么呢?
Filter接口:功能——对请求和响应进行增强,或者进行拦截。
-
JavaWEB中的过滤器运行图解
-
Filter的快速入门(重点:必须掌握)
-
Filter定义以及创建步骤介绍
-
package cn.itcast.filter; 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; /** * @author wjn * 总结:过滤器书写步骤 * 第一:创建类实现接口——DemoFilter implements Filter * 第二:过滤任务写在doFilter方法中 * 第三:web.xml中配置 */ public class @Override //销毁的方法 public void destroy() { } @Override //执行过滤的方法 public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { System.out.println("DemoFilter.....doFilter...."); } @Override //初始化的方法 public void init(FilterConfig arg0) throws ServletException { } }
Filter 是在 Web 应用程序的部署描述符中配置的——过滤器创建好之后,需要在web.xml中做配置
-
在web.xml文件中配置过滤器
<filter> <filter-name>DemoFilter</filter-name> <filter-class>cn.itcast.filter.DemoFilter</filter-class> </filter> <filter-mapping> <filter-name>DemoFilter</filter-name> <url-pattern>/1.txt</url-pattern> </filter-mapping>
-
Filter拦截操作效果
-
过滤器放行的对象:FilterChain功能介绍
FilterChain的doFilter方法:
代码实现
过滤器放行执行过程:
-
Filter生命周期
为什么要学习生命周期?
(servlet,只有知道servlet是在什么时候创建和什么时候销毁,才能知道,我在什么时候可以使用servlet)
我需要知道servlet存活的时间,才能正确的使用servlet对象。
对于过滤器,我们同样要知道,过滤器什么时候被创建,什么时候被销毁,我们才能正确的使用过滤器。
-
Filter生命周期
回顾servlet的生命周期:
创建: 第一次被访问的时候
销毁: 服务器关闭的时候,或者当前项目从服务器中移除
回顾session的生命周期:
创建: 第一次调用getsession方法
销毁: 服务器非正常关闭,超过生存时间,调用销毁(自杀)的方法
Filter:
创建:在服务器启动的时候
服务器启动截图:
销毁: 在服务器关闭的时候,过滤器销毁。
服务器关闭截图:
-
FilterConfig介绍
servletConfig对象:获取servlet相关的配置信息。FilterConfig定义:获取filter相关的配置信息。
API介绍:
API代码演示:
1)设置过滤器初始化参数
2)通过filterconfig对象来获取参数
参数配置:
效果演示:
同学提问:filter是不是单例的?
-
类比servlet,我们通过什么来测试,servlet是单例的?
测试单例的思路:
-
设置一个成员变量在过滤器中
-
发送两次请求,都去操作成员变量
-
如果前一次请求操作的结果,影响后一次请求获取到的成员变量,那么filter就是单例的,反之,不是单例。
-
Filter配置详解(web.xml中的配置)
-
关于url-pattern配置
-
过滤器如何匹配请求的路径?
回顾servlet的url-pattern:
全路径匹配——
地址栏:localhost:8080/项目根路径/资源路径 localhost:8080/itcast-filter2/1.txt
通配符的匹配——
地址栏:localhost:8080/项目根路径/abc/*
以上两种匹配方式,配置路径的时候必须以"/"开头
后缀名匹配——/路径/*.do: *.do *.txt *.action
地址栏:localhost:8080/项目根路径/*.txt
后缀名匹配方式,配置路径的时候不能以"/"开头
Filter的url-pattern配置与servlet一致。
过滤器的执行顺序?
测试方式:
-
两个过滤器,拦截同一个请求
-
调整两个过滤器的配置,再来看执行的顺序
总结:
过滤器执行的顺序是按照,web.xml中filter-mapping标签的书写顺序执行(从上往下执行)
-
关于servlet-name配置
什么是servlet-name配置?
定义:针对指定的servlet进行拦截或者增强操作的配置
Servlet:
package cn.itcast.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DemoServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("DemoServlet.....执行......."); } public void doPost(HttpServletRequest request, HttpServletResponse throws ServletException, IOException { doGet(request, response); } }
Filter:
package cn.itcast.filter; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * @author wjn * 1:定义一个类,实现javax.servlet.Filter; * 2:要进行拦截或者增强的代码,要写在doFilter方法中 * 3:在web.xml中做配置 */ public class @Override//初始化的方法 public void init(FilterConfig config) throws ServletException { System.out.println("MyFilter....init...."); //获取过滤器名称 //选中要输出的内容,按住alt,点击两次右斜线 System.out.println("FilterName:"+config.getFilterName()); //获取指定的初始化参数 String plane = config.getInitParameter("plane"); System.out.println("plane:"+plane); String train = config.getInitParameter("train"); System.out.println("train:"+train); //获取所有初始化参数的名称 Enumeration<String> enumeration = config.getInitParameterNames(); while(enumeration.hasMoreElements()){ System.out.println(enumeration.nextElement()); } } @Override//执行过滤任务的方法 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("MyFilter.....doFilter....."); //chain:是放行请求和响应的对象 chain.doFilter(request, response); } @Override//销毁的方法 public void destroy() { System.out.println("MyFilter....destroy...."); } }
Web.xml配置:
怎么想公司里的老司机请教:
-
我现在在做一个什么功能。
-
现在出现了什么状况(报错,页面显示,什么都没有发生)
-
我预期的效果是什么(我的思路是什么)
-
Filter案例--自动登录(重点:必须掌握)
-
分析
自动登陆的功能需求?
用户懒,不想输入用户名和密码,希望,访问网站,直接自动登陆
用户的使用场景:
用户点击网站,访问项目根路径的时候,启动自动登陆
实现思路:
-
用户在第一次登陆网站,保存用户名和密码(使用Cookie技术)
-
第二次访问网站,先访问根路径,启动自动登陆的功能(使用过滤器技术,在请求到达项目根路径之前完成自动登陆)
画图分析:
工作的时候,自动登陆功能,设置一定要慎重。
人人网,微博,论坛,贴吧,可以设置自动登录
银行,企业内网,支付系统,安全系统(国家网络应用,交通信号灯等),慎重选择制作自动登陆
自动登陆功能,本身就是不安全。
数据保存在cookie中,都是保存在用户的个人电脑中。
提供一个用户选择自动登录的选项,修改页面
-
LoginServlet实现
package cn.itcast.web; import java.io.IOException; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.domain.User; import cn.itcast.service.UserService; import cn.itcast.service.impl.UserServiceImpl; public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); //第一步:接受参数 String username = request.getParameter("username"); String pwd = request.getParameter("pwd"); //第二步:调用service方法登录用户 UserService userService = new UserServiceImpl(); User loginUser = userService.login(username ,pwd); //第三步:接收返回值,根据不同返回值不同处理(User == null != null) if(loginUser == null){ request.setAttribute("msg", "用户名或者密码错误"); request.getRequestDispatcher("/login.jsp").forward(request, response); return; } //登录成功 //需求:在登录页面显示用户名 /* * 第一步:登录成功之后,先记住用户名,通过cookie技术,通过response对象将cookie发送给浏览器 * * 第二步:在登录页面解析cookie,使用EL表达式的内置对象(cookie),再使用javascript进行解码 * */ //=================================自动登录修改========================= String remember = request.getParameter("remember"); if("on".equals(remember)){ //表示用户需要记住用户名和密码自动登录 Cookie c = new Cookie("username", URLEncoder.encode(loginUser.getName(), "utf-8")); c.setMaxAge(60*60*24*7); c.setPath("/"); response.addCookie(c); Cookie c2 = new Cookie("password",pwd ); c2.setMaxAge(60*60*24*7); c2.setPath("/"); response.addCookie(c2); }else{ //用户不需要自动登录 Cookie c = new Cookie("username",""); c.setMaxAge(0); c.setPath("/"); response.addCookie(c); Cookie c2 = new Cookie("password","" ); c2.setMaxAge(0); c2.setPath("/"); response.addCookie(c2); } //=================================自动登录修改========================= request.getSession().setAttribute("loginUser", loginUser); //response.sendRedirect(request.getContextPath()+"/findAllContact"); //response.sendRedirect(request.getContextPath()+"/queryPage?pageNum=1"); response.sendRedirect(request.getContextPath()+"/queryPage2?pageNum=1"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
-
过滤器实现
package cn.itcast.filter; import java.io.IOException; import java.net.URLDecoder; 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.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.domain.User; import cn.itcast.service.UserService; import cn.itcast.service.impl.UserServiceImpl; publicclass AutologinFilter implements Filter{ @Override publicvoid destroy() { } @Override publicvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //第一步: 获取数据 (cookie username password) //HttpServletRequest? HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse)response; Cookie[] cookies = req.getCookies(); if(cookies == null){ res.sendRedirect(req.getContextPath()+"/login.jsp"); return; }else{ //将cookie中的username和password String username = ""; String password = ""; for (Cookie cookie : cookies) { if("username".equals(cookie.getName())){ username = URLDecoder.decode(cookie.getValue(), "utf-8") ; } if("password".equals(cookie.getName())){ password = cookie.getValue(); } } if(username.equals("") || password.equals("")){ res.sendRedirect(req.getContextPath()+"/login.jsp"); return; }else{ //第二步:调用方法(UserService.login()) UserService userService = new UserServiceImpl(); User loginUser = userService.login(username, password); //第三步:根局不同返回值,不同处理 if(loginUser == null){ res.sendRedirect(req.getContextPath()+"/login.jsp"); return; }else{ req.getSession().setAttribute("loginUser", loginUser); res.sendRedirect(req.getContextPath()+"/queryPage2?pageNum=1"); return; } } } } @Override publicvoid init(FilterConfig arg0) throws ServletException { } }
web.xml配置:
<!-- =======================过滤器配置=============================== --> <filter> <filter-name>AutologinFilter</filter-name> <filter-class>cn.itcast.filter.AutologinFilter</filter-class> </filter> <filter-mapping> <filter-name>AutologinFilter</filter-name> <!-- 因配置文件中默认的主页index.jsp,所访问根路径的时候,默认会跳转到主页上,所以,我们配置 url-pattern使用index.jsp --> <url-pattern>/index.jsp</url-pattern> </filter-mapping> <!-- =======================过滤器配置=============================== -->
-
案例--解决day14_Contact项目中乱码
需求:请求参数在每一个servlet中单独中文乱码处理,代码重复
优化的思路,使用一个过滤器,在请求到达servlet之前,先对象request对象进行设置编码
要对所有的请求都要进行设置编码,都要拦截,进行增强,url-pattern:/*
过滤器代码:
package cn.itcast.filter; 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.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class EncodingFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 强制转换request response HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse)response; //处理响应乱码 res.setContentType("text/html;charset=utf-8"); //处理POST请求乱码 req.setCharacterEncoding("utf-8"); chain.doFilter(req, res); } @Override public void destroy() { } }
Web.xml配置:
补充(装饰(包装)设计模式口诀):
-
定义一个类,实现被装饰对象的接口
-
定义一个成员变量,记住被装饰对象的引用
-
定义构造方法,传入被装饰对象的实例
-
改写要修改的方法
-
不需要改写的方法,调用被装饰对象的原来的方法
补充:什么时候使用装饰设计模式
当我们需要对一个类进行增强的时候,增强后的类不再当前类的范畴(animal类型 cat dog都属于动物类型中可以使用继承,电子狗,不属于动物范围,所以选择使用包装设计模式 )中
复杂过滤器实现:
package cn.itcast.filter; 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.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.domain.MyRequest; public class EncodingFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 强制转换request response HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse)response; //处理响应乱码 res.setContentType("text/html;charset=utf-8"); //自定义一个request对象:MyRequest,对服务器原来的request进行增强,使用装饰设计模式 //要增强原来的request对象,必须先获取到原来的request对象 MyRequest myrequest = new MyRequest(req); //注意:放行的时候应该,传入增强后的request对象 chain.doFilter(myrequest, res); } @Override public void destroy() { } }
自定义增强类:
package cn.itcast.domain; import java.io.UnsupportedEncodingException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; //第一问题:HttpServletRequestWrapper他是什么? //HttpServletRequestWrapper:它实现了HttpServletRequest接口,继承当前对象之后,也是HttpServletRequest接口的实现类 //第一问题:增强request,可以直接实现接口,为什么要继承HttpServletRequestWrapper? //因为HttpServletRequestWrapper,已经实现了接口的方法,我们只需继承就可以使用, //如果需要对某些方法增强,只需要修改部分方法即可,其他,调用父类的方法就完成了 /** * 补充(装饰(包装)设计模式心法): 1) 定义一个类,实现被装饰对象的接口 2) 定义一个成员变量,记住被装饰对象的引用 3) 定义构造方法,传入被装饰对象的实例 4) 改写要修改的方法 5) 不需要改写的方法,调用被装饰对象的原来的方法 * */ //1) 定义一个类,实现被装饰对象的接口 public class MyRequest extends HttpServletRequestWrapper{ //2) 定义一个成员变量,记住被装饰对象的引用 private HttpServletRequest request = null; //3) 定义构造方法,传入被装饰对象的实例 //设置一个标记,用来防止,编码多次运行,要保证get方式编码,只运行一次 private boolean flag = false; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } //4) 改写要修改的方法 //所有获取参数的方法,都需要改写 @Override public Map<String, String[]> getParameterMap() { //先判断请求的方式——每一次请求,只会有一种请求方式post get String method = this.request.getMethod(); if("post".equalsIgnoreCase(method)){ //post请求方式 try { this.request.setCharacterEncoding("utf-8"); return this.request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return super.getParameterMap(); } }else if("get".equalsIgnoreCase(method)){ //先获取所有的数 Map<String, String[]> map = this.request.getParameterMap(); if(map == null){ return super.getParameterMap(); } //如果flag是false,说明没有执行过,执行中文乱码处理 //如果flag是true,说明执行过乱码处理,不再重复 if(flag){ return map; } //遍历循环map集合,将每一个数据进行中文乱码处理 //循环map集合的时候,先获取所有key的Set集合,然后,根据key,获取value值 //当前循环结束,map集合中所有数据处理完成 for (String key : map.keySet()) { //获取的数据是String数组 String[] value = map.get(key); //当前for循环结束之后,value中的数据全部处理完成 for(int i = 0 ;i< value.length ;i++){ try { String temp = new String(value[i].getBytes("iso-8859-1"),"utf-8"); //再存入原来的位置 value[i] = temp; } catch (UnsupportedEncodingException e) { e.printStackTrace(); //这里还在继续循环,所以不能return结束 } } } //循环结束,标记设置为true flag = true; return map; }else{ return super.getParameterMap(); } } @Override public String[] getParameterValues(String name) { //先获取所有的数据,map Map<String, String[]> map = this.getParameterMap(); if(map == null){ return super.getParameterValues(name); } //获取map集合中指定数据,根据name指定,相当于key String[] values = map.get(name); return values; } @Override public String getParameter(String name) { //获取指定请求参数的数组 String[] values = this.getParameterValues(name); if(values == null){ return super.getParameter(name); } JavaWeb核心之Servlet
-