过滤器和监听器
一、Servlet过滤器
1、什么是过滤器
Servlet过滤器和Servlet十分相似,但它具有拦截客户端请求的功能,Servlet过滤器可以改变请求中的内容,来满足实际开发中的需要。对于开发人员而言,过滤器实际上就是在Web应用服务器上的Web组件,用于拦截客户端(浏览器)与目标资源的请求,并对这些请求进行一定过滤处理再发送给目标资源。
如果一个Web应用中使用一个过滤器不能解决实际中的业务需要,那么可以部署多个过滤器,对业务请求进行多次处理,这样就组成了过滤链。
2、过滤器核心对象
过滤对象是放置在javax.servlet包中,其名称为Filter,它是一个接口。除了这个接口后,与过滤器相关的对象还有FilterConfig对象与FilterChain对象,这两个对象也是接口对象,位于javax.servlet包中,分别为过滤器的配置对象与过滤器的传递工具。在实际的开发中,定义过滤器对象只需要直接或间接的实现Filter接口即可。
Filter接口:
每个过滤器对象只需要直接或间接的实现Filter接口,在Filter接口中定义了3个方法,分别为init()方法、doFilter()方法和destroy()方法,其方法声明及说明如下:
public void init(FilterConfig config)throws ServletException:过滤器初始化方法,该方法在过滤器初始化时调用。
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws IOException:对请求进行过滤处理
public void destroy():销毁方法,以便释放资源。
FilterConfig接口
FilterConfig接口由Servlet容器进行实现,主要用于获取过滤器的配置信息,其方法声明及说明如表:
public String getFilterName():获取过滤起的名字。
public ServletContext getServletContext():获取Servlet上下文。
public String getInitParameter(String name):获取过滤器的初始化参数值。
public Enumeration getInitParameterNames():获取过滤器的所有初始化参数值。
FilterChain接口
FilterChain仍然由Servlet容器进行实现,在这个接口中有只有一个方法,其方法声明如下:
public void doFilter(ServletRequest request,ServletResponse response):该方法用于将过滤后的请求传递给下个过滤器,如果此过滤器已经是个过滤器链中的最后一个过滤器,那么,请求将传送给目标资源。
3、过滤器的的创建于配置
创建一个过滤器对象需要实现javax.servlet.Filter接口,同时实现接口的三个方法。
使用过滤器并不一定将请求传递给下个过滤器或目标资源,如果业务需要,也可以在过滤处理后,直接回应客户端。
过滤器与Servlet十分相似,在创建之后同样需要对其进行配置,过滤器的配置主要分为两步骤,分别为声明过滤器和创建过滤器映射。
<filter> <filter-name>MyFilter</filter-name> <filter-class>con.lyt.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping><filter>标签用于声明过滤器对象,在这个标签中必须配置两个字元素,分别为过滤器的名称和过滤器完整类名。<filter-mapping>标签用于创建过滤器的映射,它的主要作用就是指定Web应用中,哪些URL应用哪一个过滤器去处理。
4、字符编码过滤器
在Java Web开发中,由于Web容器内部使用的编码格式并不支持中文字符集,所以,处理浏览器请求中的中文数据会出现乱码现象,Web容器使用了ISO-8859-1的编码格式,所以Web应用的业务处理中也会使用ISO-8859-1的编码格式,虽然浏览器提交的请求使用的是中文编码UTF-8,但经过业务处理中的ISO-8859-1编码,仍然会出现中文乱码现象。解决此问题很简单,在业务处理中重新指定中文字符集进行编码即可解决。
例子:
@WebFilter(filterName = "CharactorFilter",urlPatterns ="/*",initParams = {@WebInitParam(name="encoding",value="UTF-8")}) public class CharactorFilter implements Filter { String encoding=null; @Override public void init(FilterConfig filterConfig) throws ServletException { encoding=filterConfig.getInitParameter("encoding"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { if(encoding!=null){ request.setCharacterEncoding(encoding); response.setContentType("text/html;charset="+encoding); } filterChain.doFilter(request,response); } @Override public void destroy() { encoding=null; } }
@WebServlet(name = "AddServlet",urlPatterns="/AddServlet") public class AddServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//处理POST请求 PrintWriter out = response.getWriter(); String id=request.getParameter("id"); String name=request.getParameter("name"); String author=request.getParameter("author"); String price=request.getParameter("price"); out.println("<h2>图书信息添加成功<h2><hr>"); out.println("图书编号:"+id); out.println("图书名称:"+name); out.println("作 者:"+author); out.println("价 格:"+price); out.flush();//刷新流 out.close();//关闭流 } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>添加图书信息</title> </head> <body> <form action="../AddServlet" name="form1" method="post"><!--action路径要加“/工程名称"+Servlet的url--> <table align="center" border="1" width="350"> <tr> <td class="2" colspan="2" align="center"> <h2> 添加图书信息</h2> </td> </tr> <tr> <td align="right">图书编号:</td> <td> <input type="text" name="id"> </td> </tr> <tr> <td align="center">图书名称:</td> <td> <input type="text" name="name"> </td> </tr> <tr> <td align="right">作 者:</td> <td> <input type="type" name="author"> </td> </tr> <tr> <td align="right">价 格:</td> <td> <input type="text" name="price"> </td> </tr> <tr> <td align="center" colspan="2" class="2"> <input type="submit" value="添加"> </td> </tr> </table> </form> </body> </html>在此程序中,不需要再在web.xml文件中对Servlet或过滤器配置了,用上面的@WebServlet注解和@WebFilter注解即可完成它们的配置。
二、Servlet监听器
在Servlet技术中已经定义了一些事件,并且可以针对这些事件编写相关的事件监听器,从而对事件作出相应的处理。例如,想要在Web应用程序启动或关闭时来执行一些任务(如数据库连接的建立和释放),或者想要监控session的创建和销毁,那么就可以通过监听器来实现。
1、Servlet监听器
监听器的作用是监听Web容器的有效事件,因此它是由容器管理的。利用Listener接口监听在容器中的某个执行程序,并且根据其应用程序的需求做出适当的响应。以下是Servlet和JS中的8个Listener和6个Event类。
Listener接口: Event类:
ServletContextListener ServletContextEvent
ServletContextAttributeListener ServletContextAttributeEvent
HttpSessionListener HttpSessionEvent
HttpSessionActivationListener HttpSessionEvent
HttpSessionAttributeListener HttpSessionBindingEvent
HttpSessionBindingListener HttpSessionBindingEvent
ServletRequestListener ServletRequestEvent
ServletRequestAttributeListener SWervletRequestAttributeEvent
2、Servlet监听器的原理
Servlet监听器是当今Web应用开发的一个重要组成部分。它在Servlet2.3规范和Servlet过滤器一起引入的,并且在Servlet2.4规范中对其进行了较大的改进,主要就是用来Web应用进行监听和控制的。
3、Servlet上下文监听
Servlet上下文监听可以监听ServletContext对象的创建、删除以及属性添加、删除和修改操作,该监听器需要用到两个接口。
(1)ServletContextListener接口:该接口存放在javax,servlet包内,它主要监听ServletContext的创建和删除,提供了2个方contextInitalized(ServletContextEvent event)方法和contextDestroy(ServletContextEvent event)方法。
(2)ServletContextAttributeListener接口:该接口存放在javax.servlet包内,主要实现监听ServletContext属性的增加、删除和修改,提供了3个方法,分别为:attributeAdded(ServletContextAttributeEvent event)方法、attributeReplaced(ServletContextAttributeEvent event)方法和attributeRemoved(ServletContextAttributeEvent event)方法。
启动监听器需要在web.xml中使用<listener>元素来配置监听器类。
4、HTTP会话监听
HTTP会话监听信息,有四个接口可以监听。
(1)HttpSessionListener接口:HttpSessionListener接口实现监听会话的创建、销毁。提供了2个方法,分别为:sessionCreated(HttpSessionEvent event)方法和sessionDestroy(HttpSessionEvent event)方法。
(2)HttpSessionAttributeListener接口:该接口实现监听HTTP会话中属性的设置要求,提供了3个方法,分别为:attributeAdded(HttpSessionBindingEvent event)方法、attributeReplaced(HttpSessionBindingEvent event)方法。
(3)HttpBindingListener接口:实现了监听HTTP会话中对象的绑定信息。它是个唯一不需要在web.xml中设定Listener的,提供了2个方法,分别为:valueBound(HttpSessionBindingEvent event)方法和valueUnBound(HttpSessionBindingEvent event)方法。
(4)HttpSessionActivationListener接口:该接口实现坚挺了HTTP会话active和passivate,提供了2个方法,分别为:sessionDidActivate(HttpSessionEvent event)方法和sessionWillPassivate(HttpSWessionEvent event)方法。
5、Servlet请求监听
在Servlet2.4规范中新增加了一个技术,就是可以监听客户端的请求。一旦能够在监听程序中获取客户端的请求,就可以就请求进行统一处理。
(1)ServletRequestListener接口:该接口提供了2个方法,分别为:requestInitalized(ServletRequestEvent event)方法和requestDestroy(ServletRequestEvent event)方法。
(2)ServletRequestAttributeListener接口:该接口提供了3个方法,分别为:attributeAdded(ServletRequestAttributeEvent event)方法、attributeReplaced(ServletRequestAtrributeEvent event)方法和attributeRemoved(ServletRequestAttributeEvent event)方法。
三、Servlet3.0新特性
1、新增注释
新增注释是Servlet3.0中的重大改革之一,通过使用注解就无需在web.xml文件中对Servlet或者过滤器进行配置。Servlet3.0新增的注释有@WebServlet、@WebFilter、@WebListener和@WebInitParam等。
(1)@WebServlet:定义在Servlet类声明之前,用于定义Servlet组件。使用该注释,就无需在web.xml文件中对Servlet进行配置。主要属性如下:
name:Servlet的name属性,等价于<servlet-name>
urlPatterns:指定一组Servlet的URL匹配模式,等价于<url-pattern>标签
initParams:指定一组Servlet初始化参数,等价于<init-param>标签
asyncSupported:声明Servlet是否支持异步操作模式,等价于<async-support>标签
例子:
@WebServlet(name = "RegisterServlet",urlPatterns = "/RegisterServlet") public class RegisterServlet extends HttpServlet { Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; public void init(ServletConfig config)throws ServletException{ try { Class.forName("com.mysql.jdbc.Driver"); conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/itcast","root","123"); if(conn!=null){ System.out.println("数据库连接成功!"); } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String name=request.getParameter("name"); String password=request.getParameter("password"); String sex=request.getParameter("sex"); String question=request.getParameter("question"); String answer=request.getParameter("answer"); String email=request.getParameter("email"); if(conn!=null){ String sql="insert into info (name,password,sex,question,answer,email) values(?,?,?,?,?,?)"; try { ps=conn.prepareStatement(sql); ps.setString(1,name); ps.setString(2,password); ps.setString(3,sex); ps.setString(4,question); ps.setString(5,answer); ps.setString(6,email); ps.execute(); PrintWriter out = response.getWriter();//获取PrintWriter对象 out.print("<h1 aligh='center'>"); out.print("注册成功!!"); out.print("</h1>"); out.flush();//刷新流 out.close();//关闭流 } catch (SQLException e) { e.printStackTrace(); }finally { if (rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps!=null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }else{ System.out.println("连接失败!!"); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>注册用户信息</title> </head> <body> <form action="../RegisterServlet" method="post" οnsubmit="return reg(this)"> <table align="center" border="1" width="500"> <tr> <td colspan="2" align="center"><b>用户注册</b></td> </tr> <tr> <td align="right" width="30%">用户名:</td> <td> <input type="text" name="name"> </td> </tr> <tr> <td align="right">密 码:</td> <td> <input type="password" name="password"> </td> </tr> <tr> <td align="right">确认密码:</td> <td> <input type="password" name="repassword"> </td> </tr> <tr> <td align="right">性 别:</td> <td> <input type="radio" name="sex" value="女" checked="女">女 <input type="radio" name="sex" value="男">男 </td> </tr> <tr> <td align="right">密码找回问题:</td> <td> <input type="text" name="question" class="box"> </td> </tr> <tr> <td align="right">密码找回答案:</td> <td> <input type="text" name="answer"> </td> </tr> <tr> <td align="right">邮 箱:</td> <td> <input type="text" name="email" class="box"> </td> </tr> <tr> <td colspan="2" align="center" height="40"> <input type="submit" value="注册"> <input type="reset" value="重置"> </td> </tr> </table> </form> </body> </html>(2)@WebFilter:用于声明过滤器,该注解会在部署是被容器处理,容器根据具体的属性配置将相应的类部署为过滤器。其属性也包含很多属性如下:
filterName:指定过滤器的name的属性,等价于<filter-name>标签
urlPatterns:指定一组Servlet的URL匹配模式,等价于<url-pattern>标签
initParams:指定一组Servlet初始化参数,等价于<init-param>标签
asyncSupported:声明Servlet是否支持异步操作模式,等价于<async-support>标签
ServletNames:指定过滤器将应用于哪些Servlet。等价于<servlet-name>标签
(3)@WebListener该注释用于声明监听器,还可以用于充当给定Web应用上下文中各种Web应用事件的监听器的类,可以使用@WebListener来标注一个实现的ServletContextListener、ServletContextAttributeListener、ServletRequestListener、ServletRequestAttributeListener、HttpSessionListener和HttpSessionAttributeListener的类。@WebListener注释有一个value属性,该属性为可选属性,用于描述监听信息。使用该注释就不需要在web.xml文件里配置<Listener>标签了。
(4)@WebInitParam:该注释等价于web.xml文件中的<servlet>和<filter>的<init-param>子标签,该注释通常不单独使用,而是配合@WebServlet或者@WebFilter使用,,常用属性如下:
name:指定参数的名字,等价于<param-name>
value:指定参数的值,等价于<param-value>
description:关于参数的描述,等价于<description>
@WebFilter(filterName = "CharactorFilter",urlPatterns ="/*",initParams = {@WebInitParam(name="encoding",value="UTF-8")})
2、对文件上传的支持
在Servlet3.0出现之前,处理文件上传是一件非常麻烦的事,因为需要借助第三方组件,例如:commons.fileupload等。实现文件上传需要以下两项内容:
(1)需要添加@MultipartConfig注释
(2)从request对象中获取Part文件对象。
@MultipartConfig注释需要标注在@WebServlet之上,其具有属性如下:
fileSizeThreshold:当数据量大于该值时,内容将写入文件。
location:存放生成文件的地址。
maxFileSize:允许上传的文件最大值。默认值为-1,表示没有限制。
maxRequestSize:针对该multipart/form-data请求的最大数量,默认值为-1,表示没有限制。
例子:
@MultipartConfig(location = "d:/myfile1.txt") @WebServlet(name = "UploadServlet",urlPatterns = "/UploadServlet") public class UploadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out=response.getWriter(); String path = this.getServletContext().getRealPath("/");//获取服务器的地址 Part p = request.getPart("file1");//获取用户选择上传的文件 if(p.getContentType().contains("image")){//仅处理上传的图片文件 ApplicationPart ap = (ApplicationPart) p; String fname1=ap.getFileName(); int path_idx=fname1.lastIndexOf("\\")+1; String fname2=fname1.substring(path_idx,fname1.length()); p.write(path+"/upload"+fname2); out.write("文件上传成功"); }else{ out.write("请选择文件!!!"); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } }
<body> <form action="../UploadServlet" method="post" name="form1" enctype="multipart/form-data"> 选择文件<input type="file" name="file1" id="file1"> <input type="submit" name="upload" value="上传"> </form> </body> </html>