过滤器 ,就是浏览器发出请求到servlet的中间路径上进行拦截;
servlet处理后的响应还会经过该过滤器
- 作用
- 对一些敏感词汇进行过滤
- 统一设置编码
- 自动登录
如何使用Filter
- 定义一个类, 实现Filter
//使用注解
@WebFilter("*")
public class DemoFilter implements Filter {
public DemoFilter() {
}
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
System.out.println("来到过滤器");
chain.doFilter(request, response);
//服务器响应也会经过滤器
response.getWriter().append("hello filter");
}
public void init(FilterConfig fConfig) throws ServletException {}
}
- 注册过滤器
在web.xml里面注册,注册的手法与servlet基本一样。
<filter>
<display-name>
FilterDemo
</display-name>
<filter-name>
FilterDemo
</filter-name>
<filter-class> com.itheima.filter.FilterDemo </filter-class>
</filter>
<filter-mapping>
<filter-name>
FilterDemo
</filter-name>
<url-pattern>/ * </url-pattern>
<dispatcher>FORWARD |REQUEST</dispatcher>
</filter-mapping>
Filter的生命周期
- 创建:在服务器启动的时候就创建。
- 销毁:服务器停止的时候。
Filter执行顺序
-
客户端发出请求,先经过过滤器, 如果过滤器放行,那么才能到servlet
-
如果有多个过滤器, 那么他们会按照注册的映射顺序 来 排队。 只要有一个过滤器, 不放行,那么后面排队的过滤器以及servlet都不会收到请求。
Filter细节:
- init方法的参数 FilterConfig , 可以用于获取filter在注册时的名字,以及初始化参数。其实这里的设计的初衷与ServletConfig是一样的。
- 如果想放行,那么在doFilter 方法里面操作,使用参数 chain
chain.doFilter(request, response); 放行, 让请求到达下一个目标。
-
/* 写法格式与servlet一样。
- 全路径匹配 以 / 开始
/LoginServlet
- 以目录匹配 以 / 开始 以 * 结束
/demo01/*
- 以后缀名匹配 以 * 开始 以后缀名结束
*.jsp *.html *.do
- 全路径匹配 以 / 开始
-
针对 dispatcher 设置
如果是多种用|
分割
- REQUEST : 只要是请求过来,都拦截,默认就是REQUEST
- FORWARD : 只要是转发都拦截。
- ERROR : 页面出错发生跳转
- INCLUDE : 包含页面的时候就拦截。
自动登录
- 需求分析
1. 搭建环境
- 搭建数据库
- 搭建页面
访问login.jsp页面,登录servlet代码
@WebServlet("/LoginServlet")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
try {
String userName = request.getParameter("username");
String password = request.getParameter("password");
String autoLogin = request.getParameter("auto_login");
UserBean user = new UserBean();
user.setUsername(userName);
user.setPassword(password);
UserDao dao = new UserDaoImpl();
UserBean userBean = dao.login(user);
if (userBean != null) {
//如果选择自动登录,那么就将用户名和密码放到cookie发送到客户端
if ("on".equals(autoLogin)) {
//发送cookie给客户端
Cookie cookie = new Cookie("auto_login", userName + "#" + password);
cookie.setMaxAge(60 * 60 * 24 * 7); //7天有效期
cookie.setPath("/AutoLoginDemo");
//cookie.setPath(request.getContextPath());
response.addCookie(cookie);
}
//成功了,进入首页
request.getSession().setAttribute("userBean", userBean);
response.sendRedirect("index.jsp");
} else {
//不成功,重新进入登录页
request.getRequestDispatcher("login.jsp").forward(request, response);
}
} catch(SQLException e) {
e.printStackTrace();
}
}
访问index页面,使用filter完成自动登录
过滤器的核心不是完全拦截 , 而是放行显示。 它的核心是在放行之前,帮用户完成登录的功能。
- 实现思路
- 访问index页面,先判断session是否有效, 如果有效,就不用取cookie了,直接放行,显示登录成功
- 如果session失效了,那么就取 cookie;(因为session在关闭浏览器后会失效)
- 没有cookie 放行 ,显示请登录
- 有cookie
取出来cookie的值,然后完成登录
把这个用户的值存储到session中
放行,显示登录成功
@WebFilter("*")
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
try {
HttpServletRequest request = (HttpServletRequest) req;
//先判断,现在session中有没有userBean.
UserBean userBean = (UserBean) request.getSession().getAttribute("userBean");
//session存在,进入index页面,显示登录成功
if (userBean != null) {
chain.doFilter(request, response);
} else {
//代表session失效了。
//2. 看cookie。
//1. 来请求的时候,先从请求里面取出cookie , 但是cookie有很多的key-value
Cookie[] cookies = request.getCookies();
//2. 从一堆的cookie里面找出我们以前给浏览器发的那个cookie
Cookie cookie = CookieUtil.findCookie(cookies, "auto_login");
//第一次来
if (cookie == null) {
//进入index页面,显示请登录
chain.doFilter(request, response);
} else {
//不是第一次;应该是关闭浏览器后重新进入
String value = cookie.getValue();
String username = value.split("#")[0];
String password = value.split("#")[1];
//完成登录
UserBean user = new UserBean();
user.setUsername(username);
user.setPassword(password);
UserDao dao = new UserDaoImpl();
userBean = dao.login(user);
//使用session存这个值到域中,方便下一次未过期前还可以用。
request.getSession().setAttribute("userBean", userBean);
//显示登录登录成功
chain.doFilter(request, response);
}
}
} catch(Exception e) {
e.printStackTrace();
chain.doFilter(req, response);
}
}
BeanUtils的使用
需要的jar
commons-beanutils-1.8.3.jar
commons-logging-1.1.1.jar
作用:将map对象中的键值对,组装成一个bean对象
BeanUtils.populate(bean, map);
//数据源
Map map = request.getParameterMap();
//声明bean对象
UserBean bean = new UserBean();
//将map对象转换为bean对象
BeanUtils.populate(bean, map);
//直接输出bean
System.out.println(bean);
但是,该方法不支持字符串到日期的转换,在该方法执行前,需要注册自定义日期转换器;或者是其他类型的数据也需要自定义转换。
//注册自己的日期转换器
ConvertUtils.register(new MyDateConverter(), Date.class);
public class MyDateConverter implements Converter {
@Override
// 将value 转换 c 对应类型
// 存在Class参数目的编写通用转换器,如果转换目标类型是确定的,可以不使用c 参数
public Object convert(Class c, Object value) {
String strVal = (String) value;
// 将String转换为Date --- 需要使用日期格式化
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = dateFormat.parse(strVal);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}