Web-第十八天 过滤器Filter【悟空教程】
今日内容介绍
今日内容学习目标
在完成登录时,如果用户勾选“自动登录”,将在下次登录时,自动完成登录功能,减少用户再次输入账号和密码繁琐的操作。此功能是对用户的操作体验进行优化,本案例将带领大家完成此功能。效果图如下:
自动登陆:有程序帮助使用者,进行自动的登录。(输入用户名和密码,点击登录这个操作)
登录:成功 (session作用域记录用户登录状态),失败(在request作用域记录用错误信息)
//实现类
public class HelloFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//放行
chain.doFilter(request, response);
}
public void destroy() {
}
}
//xml配置
<!-- 1 注册:通知tomcat过滤器实现类
filter-name:给已经注册的过滤器进行唯一命名
filter-class: 过滤器实现类,全限定类名
-->
<filter>
<filter-name>HelloFilter</filter-name>
<filter-class>cn.com.javahelp.demo01.HelloFilter</filter-class>
</filter>
<!-- 2 使用:确定对那些程序使用过滤器
filter-name:已经注册的过滤器名称
url-pattern:需要对那些指定路径进行过滤 。
/* 表示所有
-->
<filter-mapping>
<filter-name>HelloFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
用户登录成功后,如果用户勾选复选框,将使用cookie记录用户信息,cookie的值格式“用户名@密码”。
当用户第二次访问首页时,编写过滤器处理浏览器cookie记录的用户信息。
<!-- 连接数据库的4项基本参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/day24_db</property>
<property name="user">root</property>
<property name="password">1234</property>
#创建数据库
create database day24_db;
#使用数据库
use day24_db;
### 用户表
CREATE TABLE `user` (
`uid` varchar(32) PRIMARY KEY,
`username` VARCHAR(20) ,
`password` VARCHAR(20) ,
`gender` VARCHAR(10) , #性别
`telephone` VARCHAR(20) ,
`email` VARCHAR(50) ,
`introduce` VARCHAR(100), #自我介绍
`activeCode` VARCHAR(50) , #激活码
`state` INT(11) , #激活状态 0:未激活 1:激活
`role` VARCHAR(10) DEFAULT '普通用户' ,#角色(权限管理)
`registTime` DATETIME
);
insert into user(uid,username,password) values('u001','jack','1234');
insert into user(uid,username,password) values('u002','rose','1234');
insert into user(uid,username,password) values('u003','张三','1234');
public class User {
private String uid;
private String username;
private String password;
private String gender;
private String telephone;
private String email;
private String introduce;
private String activeCode;
private String state;
private String role;
private String registTime;
作者:[西汉]司马迁 著 张燕均,富强 改编
当当 广告
购买
/**
* 通过用户名和密码查询用户
* @param username
* @param password
* @return
*/
public User find(String username,String password){
try {
//1 核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2 准备sql语句
String sql = "select * from user where username = ? and password = ?";
//3 准备参数
Object[] params = {username ,password};
//4 执行
return queryRunner.query(sql, new BeanHandler<User>(User.class), params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public class UserService {
private UserDao userDao = new UserDao();
/**
* 用户登录
* @param user
* @return
*/
public User login(User user){
return userDao.find(user.getUsername(), user.getPassword());
}
}
<form action="${pageContext.request.contextPath}/userLoginServlet" method="post" >
<input type="text" name="username" placeholder="请输入用户名">
<input type="password" name="password" placeholder="请输入密码">
<input type="checkbox" name="autoLogin"> 自动登录
<input type="submit" width="100" value="登录">
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//0 编码
request.setCharacterEncoding("UTF-8");
//1 获得数据,并封装
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = new User(username,password);
//2 用户登录
UserService userService = new UserService();
User loginUser = userService.login(user);
//3 处理信息
if(loginUser != null) {
// 3.1 用户登陆成功
// * 将用户信息保存在session作用域,记录登录状态
request.getSession().setAttribute("loginUser", loginUser);
// * 重定向到首页
response.sendRedirect(request.getContextPath() + "/index.jsp");
} else {
// 3.2 登录不成功
// * 用户错误提示信息
request.setAttribute("msg", "用户名和密码不匹配");
// * 请求转发到登录页
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
<servlet>
<servlet-name>UserLoginServlet</servlet-name>
<servlet-class>cn.com.javahelp.web.servlet.UserLoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserLoginServlet</servlet-name>
<url-pattern>/userLoginServlet</url-pattern>
</servlet-mapping>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:if test="${not empty msg}">
<div>
<label for="username" class="col-sm-2 control-label"></label>
<div>
<font style="color: #f00;font-weight: bold;">${msg}</font>
</div>
</div>
</c:if>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:if test="${empty loginUser}">
<a href="login.jsp">登录</a>
</c:if>
<c:if test="${not empty loginUser}">
${loginUser.username} ,
<a href="#">退出</a>
</c:if>
<input name="username" placeholder="请输入用户名" value="${user.username}">
<input name="password" placeholder="请输入密码" value="${user.password}">
效果
<input type="checkbox" name="autoLogin"> 自动登录
/**自动登录start*/
// #1 获得复选框,如果没有设置value值,默认获得on
String autoLogin = request.getParameter("autoLogin");
if(autoLogin != null){
//#2 使用cookie记录用户信息,使用@拼凑
Cookie cookie = new Cookie("autoLoginCookie", username + "@" + password);
cookie.setPath("/");
cookie.setMaxAge(60*60);
response.addCookie(cookie);
}
/**自动登录end*/
1. 如果已经登录,不进行自动登录
2. 如果浏览器没有自动登录cookie信息,不进行自动登录
3. 如果浏览器记录cookie有误,不进行自动登录
4. 用户没有登录,浏览器记录正确的cookie,将自动完成登录(session记录状态)
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
//0 强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//1 用户登录信息
User loginUser = (User) request.getSession().getAttribute("loginUser");
//2 如果已经登录,放行,不需要自动登录
if(loginUser != null){
chain.doFilter(request, response);
return; //程序结束
}
//3 获得 自动登录 cookie信息
Cookie[] allCookie = request.getCookies();
Cookie userCookie = null;
if(allCookie != null){
for (Cookie c : allCookie) {
if("autoLoginCookie".equals(c.getName())){
userCookie = c;
break;
}
}
}
//4 判断自动登录cookie是否存在,如果没有cookie,不需要自动
if(userCookie == null){
chain.doFilter(request, response);
return;
}
//5 通过用户cookie中记录信息,查询用户
// 5.1 获得用户信息
String[] u = userCookie.getValue().split("@");
String username = u[0];
String password = u[1];
User user = new User(username, password);
// 5.2 执行登录
UserService userServic = new UserService();
loginUser = userServic.login(user);
//6 如果没有查询(修改密码
if(loginUser == null){
chain.doFilter(request, response);
return ;
}
// 7 自动登录
request.getSession().setAttribute("loginUser", loginUser);
//放行
chain.doFilter(request, response);
}
l 步骤4:编写过滤器 xml配置
<!-- 登录拦截器start -->
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>cn.com.javahelp.web.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 登录拦截器end -->
// 获得初始化参数:过滤器的初始化参数.
String username = fConfig.getInitParameter("username");
String password = fConfig.getInitParameter("password");
System.out.println("初始化参数"+username+" "+password);
// 获得所有的初始化参数的名称:
Enumeration<String> names = fConfig.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = fConfig.getInitParameter(name);
System.out.println(name+" "+value);
}
// 获得过滤器的配置的名称:
String filterName = fConfig.getFilterName();
System.out.println("过滤器名称"+filterName);
过滤器链中的过滤器的执行的顺序跟<filter-mapping>的配置顺序有关
* 三种配置:
* 完全路径匹配:以 / 开始 /aaa /aaa/bbb
* 目录匹配: 以 / 开始 /* /aaa/*
* 扩展名匹配: 不能以 / 开始 *.do *.jsp *.action
* REQUEST :默认值.
* FORWARD :拦截转发
* ERROR :拦截跳转到错误页面.全局错误页面.
* INCLUDE :拦截在一个页面中包含另一个页面.
在完成功能时,我们发现UserLoginServlet有一行代码,在之前编写的servlet都出现了,那就是编码处理,在实际开发中,需要统一处理编码。且之前的程序GET请求需要单独处理,本案例将以上两个问题使用过滤器统一解决。也就是在servlet前后执行特定功能。
public class EncodingFilter implements Filter {
public void init(FilterConfig fConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//0 强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//1 设置编码
request.setCharacterEncoding("UTF-8");
//2 放行
chain.doFilter(request, response);
}
public void destroy() {
}
}
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.com.javahelp.web.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
编写Request装饰者实现类,理论需要实现HttpServletRequest接口,然后提供成员变量和构造方法,对接口中所有的方法进行处理(增强或不增强),但HttpServletRequest接口中方法过多,使操作虽然简单,但比较繁琐。JavaEE规范提供了HttpServletRequest接口的装饰者实现基类HttpServletRequestWrapper,及按照装饰者编写实现类,所有方法都不增强。我们如果需要对方法进行增强,只需要继承该类,然后复写对应方法即可。
public class MyRequest extends HttpServletRequestWrapper {
public MyRequest(HttpServletRequest request) {
super(request);
}
/**
* 获得指定名称的第一个参数
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
try {
if ("GET".equalsIgnoreCase(super.getMethod())) {
value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return value;
}
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//0 强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//1 设置编码
request.setCharacterEncoding("UTF-8");
//2 创建自定义request
MyRequest myRequest = new MyRequest(request);
//3 放行,使用自定义request
chain.doFilter(myRequest, response);
}
//0 编码
//request.setCharacterEncoding("UTF-8");
<%--登录表单start --%>
<form action="${pageContext.request.contextPath}/userLoginServlet" method="get" >