过滤器是一个服务器端的组件,它可以截取客户端的请求与响应信息,并对这些信息过滤。
请求index.jsp页面,触发过滤器,执行doFilter方法,输出“start…doFilter”,filter放行,执行index.jsp,再执行dofilter余下的代码。
先创建过滤器类,然后实现Filter接口,在配置Web.xml文件
过滤器能改变用户请求的Web资源,也就是能改变用户请求的路径,但是,过滤器不能处理用户的请求
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
System.out.println("start.....doFilter----FirstFilter");
arg2.doFilter(arg0, arg1);//放行??
HttpServletRequest req = (HttpServletRequest) arg0;
HttpServletResponse response2 = (HttpServletResponse) arg1;
//重定向(相当于一个新的请求,所以在main界面继续出发FirstFilter) 陷入死循环
response2.sendRedirect(req.getContextPath()+"/main.jsp");
//请求转发,没有进入死循环,但是如果把main页面的过滤器改为forward则同样出现死循环
// req.getRequestDispatcher("main.jsp").forward(arg0, arg1);
//与上面几乎一样
// req.getRequestDispatcher("main.jsp").include(arg0, arg1);
System.out.println("end.....doFilter----FirstFilter");
}
ERROR过滤器:
<filter>
<filter-name>ErrorFilterfilter-name>
<filter-class>com.imooc.filter.ErrorFilterfilter-class>
filter>
<filter-mapping>
<filter-name>ErrorFilterfilter-name>
<url-pattern>/error.jspurl-pattern>
<dispatcher>ERRORdispatcher>
filter-mapping>
<error-page>
<error-code>404error-code>
<location>/error.jsplocation>
error-page>
AsynFilter(@WebFilter)(servlet3.0新增)
@WebFilter用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。
创建过滤器类实现Filter接口,配置@WebFilter即完成了过滤器的配置,无需手动去配置Web.xml
怎么体现异步过滤器的异步特性呢?
新建一个servlet,在内部类里设计一个线程,在里面执行一些复杂业务,模拟异步操作(servlet和filter都要设置支持异步)
从结果可以看出,过滤器并没有等待模拟的复杂业务执行(线程),而是直接执行完了过滤器。
login.jsp
<body>
<form action="<%=request.getContextPath() %>/servlet/LoginServlet" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="提交">
form>
body>
LoginServlet.java
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String uesrname = request.getParameter("username");
String password = request.getParameter("password");
//手动解决乱码
//System.out.println(new String(uesrname.getBytes("ISO-8859-1"),"UTF-8"));
//过滤器解决乱码
System.out.println(uesrname);
if ("admin".equals(uesrname)&&"admin".equals(password)) {
//校验通过
HttpSession session = request.getSession();
session.setAttribute("username", uesrname);
response.sendRedirect(request.getContextPath()+"/success.jsp");
}else {
//校验失败
response.sendRedirect(request.getContextPath()+"/fail.jsp");
}
}
到这里,已经可以实现登录,但是完全没有过滤
Login_Filter.java
public class Login_Filter implements Filter {
private FilterConfig config;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
//在过滤器内直接设置编码
//request.setCharacterEncoding("utf-8");
//过滤器设置初始化参数解决乱码
String charset = config.getInitParameter("charset");
//未指定编码时默认utf-8
if (charset==null) {
charset="utf-8";
}
request.setCharacterEncoding(charset);
String noLonginPaths = config.getInitParameter("noLonginPaths");
//通过设置初始化参数,解决多个不过滤界面问题
if (noLonginPaths != null) {
String[] strArray = noLonginPaths.split(";");
for (int i = 0; i < strArray.length; i++) {
//参数为空和null时不放行
if (strArray[i] == null || "".equals(strArray[i]))
continue;
//url.indexif(str):如果url包含str,则返回str在url中的位置,如果不包含则返回-1
if (request.getRequestURI().indexOf(strArray[i]) != -1) {
arg2.doFilter(arg0, arg1);
return;
}
}
}
//如果请求地址就是登录界面的话,或者loginServlet就放行,否则会进入死循环
//后来发现,fail.jsp也需要放行,这样一来,这里代码会变得很繁琐,以后增加新的页面还需要修改代码,不符合java设计原则
// if (request.getRequestURI().indexOf("login.jsp")!=-1
// ||request.getRequestURI().indexOf("LoginServlet")!=-1) {
// arg2.doFilter(arg0, arg1);
//返回,否则还会执行下面的代码
// return;
// }
//通过session获取用户名,如果有登录信息。就放行;否则,别人只需输入成功页面地址就可以显示登陆成功界面
//如果没有登录信息就跳转到登录界面
if (session.getAttribute("username") != null) {
arg2.doFilter(arg0, arg1);
} else {
response.sendRedirect("login.jsp");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
//通过设置初始化参数,解决多个不过滤界面问题
config = arg0;
}
}
web.xml
<filter>
<filter-name>LoginFilterfilter-name>
<filter-class>com.imooc.filter.Login_Filterfilter-class>
<init-param>
<param-name>noLonginPathsparam-name>
<param-value>login.jsp;fail.jsp;LoginServletparam-value>
init-param>
<init-param>
<param-name>charsetparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>LoginFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<description>This is the description of my J2EE componentdescription>
<display-name>This is the display name of my J2EE componentdisplay-name>
<servlet-name>LoginServletservlet-name>
<servlet-class>com.imooc.servlet.LoginServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>LoginServletservlet-name>
<url-pattern>/servlet/LoginServleturl-pattern>
servlet-mapping>
要注意这里两个主要问题(设置多个不过滤的页面和解决编码)都是通过设置初始化参数完成的!