过滤器
我们写多了servlet会发现,很多代码和功能是重复的,比如:解决中文乱码问题、权限验证、日志的记录等,他们的特点是:代码相同或相似、分散在不同位置、不利于维护。
过滤器就是他们的解决办法。
过滤器是请求到达目标之前的处理程序,也是响应离开服务器之前的处理程序。
我们可以定义多个过滤器来组成一个过滤器链,每个过滤器完成一个任务,请求和响应如图所示,依次经过过滤器,第一个过滤器最先被经过,离开时最后被经过。
这种设计使用了一个设计模式:责任链模式。
一个图秒懂
如图,功能类似的代码只有一份,便于维护。
我们如何使用过滤器呢?
1)开发过滤器类
2)指定过滤器过滤范围(有些请求不需要经过某些过滤器)
一共也就两个方法,非常简单,我们写一个解决中文乱码的过滤器吧:
public class EncodingFilter implements Filter{private String encoding;/*** 初始化操作,只执行一次*/@Overridepublic void init(FilterConfig config) throws ServletException {//先读取配置文件,获取编码类型encoding = config.getInitParameter("encoding");if(encoding == null){encoding = "utf-8";}}/*** 相当于Servlet的service(),过滤范围的每次请求响应都经过*/@Overridepublic void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws IOException, ServletException {//请求到达目标资源之前的预处理操作request.setCharacterEncoding(encoding);//调用下一个过滤器或者目标资源chain.doFilter(request, response);//响应离开服务器端之前的后处理操作(无)}/*** 销毁操作,只执行一次*/@Overridepublic void destroy() {// TODO Auto-generated method stub}}
相关配置也和servlet类似(通过kv找到utf-8):
<filter><filter-name>EncodingFilter</filter-name><filter-class>com.bjsxt.filter.EncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/servlet/*</url-pattern></filter-mapping>
我们再理解一下过滤器的执行过程:
代码中:
//请求到达目标资源之前的预处理操作
//调用下一个过滤器或者目标资源
//响应离开服务器端之前的后处理操作(无)
一共有这么三个操作,而过滤器的执行过程就是如此的
化的很丑但是就是这个意思。
再写一下怎么搞过滤范围,也超简单直接上代码了:
public class AuthFilter implements Filter{@Overridepublic void init(FilterConfig filterconfig) throws ServletException {// TODO Auto-generated method stub}/*** 过滤路径是 /servlet/* *.jsp* 某些jsp应该排除在外 * 某些servlet应该排除在外*/@Overridepublic void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httprequest = (HttpServletRequest)request; String uri = httprequest.getRequestURI();int n1 = uri.indexOf("login.jsp");// >=0 存在int n2 = uri.indexOf("register.jsp");int n3 = uri.indexOf("index.jsp");int n4 = -1;int n5 = -1;if(n1>=0 || n2>=0 ||n3>=0 ||n4>=0 ||n5>=0 ){ //假设是需要排除在外的资源//放行chain.doFilter(request, response);}else{//do something}}@Overridepublic void destroy() {// TODO Auto-generated method stub}
}
监听器
监听器是一个实现特定接口的普通Java程序,这个程序专门用于监听另一个Java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行
超简单代码例子:
package listener;import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
/**
* 记录每个请求的时间,客户端IP,URL地址到日志文件中
* @author Administrator
*
*/
public class LogListener implements ServletRequestListener,ServletRequestAttributeListener{/*** 请求结束了*/@Overridepublic void requestDestroyed(ServletRequestEvent servletrequestevent) {// TODO Auto-generated method stub}/*** 请求开始了* 其实对于图片、视频、音频、js、css也会有一个新的请求,所以也会被监听*/@Overridepublic void requestInitialized(ServletRequestEvent sre) {//获取要记录的每个请求的时间,客户端IP,URL地址Date now = new Date();HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();String addr = request.getRemoteAddr();String url = request.getRequestURL().toString(); //http://127.0.0.1:8081/myservlet/servlet/UserServletString qs = request.getQueryString(); //method=login//记录到日志文件中PrintWriter pw = null;try {pw = new PrintWriter(new FileWriter("d:/requestlog.log", true)); //if(qs!= null){pw.println("time="+now.toLocaleString()+",addr="+addr+",url="+url+"?"+qs);}else{pw.println("time="+now.toLocaleString()+",addr="+addr+",url="+url);} } catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally{pw.close();}}/*** request.setAttribute("error","用户名不能为空");**/@Overridepublic void attributeAdded(ServletRequestAttributeEvent servletrequestattributeevent) {// TODO Auto-generated method stub}/**** request.removeAttribute("error");*/@Overridepublic void attributeRemoved(ServletRequestAttributeEvent servletrequestattributeevent) {// TODO Auto-generated method stub}/*** request.setAttribute("error","用户名和密码错误");*/@Overridepublic void attributeReplaced(ServletRequestAttributeEvent servletrequestattributeevent) {// TODO Auto-generated method stub}}<listener><listener-class>listener.LogListener</listener-class></listener>