过滤器
我们写多了servlet会发现,很多代码和功能是重复的,比如:解决中文乱码问题、权限验证、日志的记录等,他们的特点是:代码相同或相似、分散在不同位置、不利于维护。
过滤器就是他们的解决办法。
过滤器是请求到达目标之前的处理程序,也是响应离开服务器之前的处理程序。
我们可以定义多个过滤器来组成一个过滤器链,每个过滤器完成一个任务,请求和响应如图所示,依次经过过滤器,第一个过滤器最先被经过,离开时最后被经过。
这种设计使用了一个设计模式:责任链模式。
一个图秒懂
如图,功能类似的代码只有一份,便于维护。
我们如何使用过滤器呢?
1)开发过滤器类
2)指定过滤器过滤范围(有些请求不需要经过某些过滤器)
一共也就两个方法,非常简单,我们写一个解决中文乱码的过滤器吧:
public class EncodingFilter implements Filter{
private String encoding;
/**
* 初始化操作,只执行一次
*/
@Override
public void init(FilterConfig config) throws ServletException {
//先读取配置文件,获取编码类型
encoding = config.getInitParameter("encoding");
if(encoding == null){
encoding = "utf-8";
}
}
/**
* 相当于Servlet的service(),过滤范围的每次请求响应都经过
*/
@Override
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//请求到达目标资源之前的预处理操作
request.setCharacterEncoding(encoding);
//调用下一个过滤器或者目标资源
chain.doFilter(request, response);
//响应离开服务器端之前的后处理操作(无)
}
/**
* 销毁操作,只执行一次
*/
@Override
public 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{
@Override
public void init(FilterConfig filterconfig) throws ServletException {
// TODO Auto-generated method stub
}
/**
* 过滤路径是 /servlet/* *.jsp
* 某些jsp应该排除在外
* 某些servlet应该排除在外
*/
@Override
public 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}
}
@Override
public 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{
/**
* 请求结束了
*/
@Override
public void requestDestroyed(ServletRequestEvent servletrequestevent) {
// TODO Auto-generated method stub
}
/**
* 请求开始了
* 其实对于图片、视频、音频、js、css也会有一个新的请求,所以也会被监听
*/
@Override
public 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/UserServlet
String 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","用户名不能为空");
*
*/
@Override
public void attributeAdded(
ServletRequestAttributeEvent servletrequestattributeevent) {
// TODO Auto-generated method stub
}
/**
*
* request.removeAttribute("error");
*/
@Override
public void attributeRemoved(
ServletRequestAttributeEvent servletrequestattributeevent) {
// TODO Auto-generated method stub
}
/**
* request.setAttribute("error","用户名和密码错误");
*/
@Override
public void attributeReplaced(
ServletRequestAttributeEvent servletrequestattributeevent) {
// TODO Auto-generated method stub
}
}
<listener>
<listener-class>listener.LogListener</listener-class>
</listener>