文章目录
1. Filter过滤器学习
1.1. Filter的生命周期
- Filter的创建:当启动服务器时Filter过滤器开始创建。
- Filter启动销毁时,Filter结束
1.2. 总结Filter的作用
- 公共代码抽取
- 可以对request和response中的方法进行增强(装饰者模式)
- 进行权限控制
2. 案例一:实现登录功能
- 登录功能画图分析
- 给前端页面添加action路径(动态的)。
<form class="form-horizontal" action="${pageContext.request.contextPath }/login" method="post">
- 给用户名,密码添加name标签用于web层获取参数
- 创建LoginServlet,获取表单参数,创建session对象,调用Service层,dao层进行查找
HttpSession session=request.getSession();
//获取数据
String username=request.getParameter("username");
String password=request.getParameter("password");
//调用service层
UserService service =new UserService();
User user=null;
try {
user=service.login(username,password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
- web层对获取的对象进行判断是否为空,若为空,就转发到登录页面继续登录,不为空,就重定向到首页
//判断用户是否存在
if(user!=null) {
//登录成功
session.setAttribute("user", user);
//重定向到首页
response.sendRedirect(request.getContextPath());//默认是首页
}else {
request.setAttribute("loginInfo","用户名或密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
- 注意重定向和分发的写法的区别。
- jsp页面中通过EL表达式获取loginInfo信息
<div>
<span style="color:red">${loginInfo }</span>
</div>
- dao层查询数据用BeanHandler这个专门是用来将查询的数据封装到Bean对象的。
public User login(String username, String password) throws SQLException {
QueryRunner runner=new QueryRunner(DataSourceUtils.getDataSource());
String sql="select * from user where username=? and password=?";
User user= runner.query(sql, new BeanHandler<User>(User.class),username,password);
return user;
}
- 修改jsp页面,登录成功要不能再显示登录页面了,要显示该用户的用户名
<c:if test="${empty user}">
<li><a href="login.jsp">登录</a></li>
<li><a href="register.jsp">注册</a></li>
</c:if>
<c:if test="${!empty user }">
<li>欢迎您,${user.username }</li>
<li><a href="#">退出</li>
</c:if>
3. 案例三:实现自动登录功能
- 自动登录画图分析
- 设置前端jsp页面,设置value和name用于web层判断是否勾选自动登录
<input type="checkbox" name="autoLogin" value="autoLogin"> 自动登录</input>
- 自动登录是要将用户登录信息设置到cookie存储的,等下一次登录时,过滤器先检查cookie,如果cookie里面有信息就拿着信息直接登录。因此,在servlet中先检查用户是否选择了自动登录,如果选择了就将用户信息存储到cookie
if(user!=null) {
//登录成功
//判断用户是否勾选自动登录
String autoLogin=request.getParameter("autoLogin");
if(autoLogin!=null) {
//说明用户要求自动登录,就要把用户的登录信息存储到cookie中
Cookie cookie_username=new Cookie("cookie_username",username);
Cookie cookie_password=new Cookie("cookie_password",password);
//设置cookie的持久化时间
cookie_username.setMaxAge(60*60);
cookie_password.setMaxAge(60*60);
//设置cookie的携带路径
cookie_username.setPath(request.getContextPath());//这个路径就是web工程路径,//也就是说凡是访问该web工程下的任何一个都要加载cookie
cookie_password.setPath(request.getContextPath());
response.addCookie(cookie_username);
response.addCookie(cookie_password);
}
- 下面就要设置过滤器了,创建一个过滤器,当登录时,先查看cookie是否有用户信息,如果有拿出来直接登录。
//由于Cookie属于HttpRequest接口的,因此需要强转
//httpServletRequest是ServletRequest的子类,而Http又丰富了一些方法,因此getCookie()父类没有。
HttpServletRequest req=(HttpServletRequest)request;
HttpServletResponse resp=(HttpServletResponse)response;
HttpSession session=req.getSession();//获取session
- 判断cookie中是否有用户信息
String cookie_username=null;
String cookie_password=null;
//获取cookie
Cookie[] cookies=req.getCookies();
if(cookies!=null) {
for(Cookie cookie:cookies) {
//获得名字是cookie_username和cookie_password
if("cookie_username".equals(cookie.getName())) {
cookie_username=cookie.getValue();
}
if("cookie_password".equals(cookie.getName())){
cookie_password = cookie.getValue();
}
}
}
- 判断cookie信息是否为空,如果不为空,就登录。
if(cookie_username!=null&&cookie_password!=null) {
//登录代码
UserService service=new UserService();
User user=null;
try {
user=service.login(cookie_username, cookie_password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//将登录的用户的user对象存到session中
session.setAttribute("user", user);
}
- 过滤器放行,必须写
chain.doFilter(req, resp);
- 配置过滤器web.xml
<filter>
<filter-name>autoLogin</filter-name>
<filter-class>com.itheima.web.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>autoLogin</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 源码
public class AutoLoginFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//由于Cookie属于HttpRequest接口的,因此需要强转
HttpServletRequest req=(HttpServletRequest)request;
HttpServletResponse resp=(HttpServletResponse)response;
HttpSession session=req.getSession();//获取session
//httpServletRequest是ServletRequest的子类,而Http又丰富了一些方法,因此getCookie()父类没有。
String cookie_username=null;
String cookie_password=null;
//获取cookie
Cookie[] cookies=req.getCookies();
if(cookies!=null) {
for(Cookie cookie:cookies) {
//获得名字是cookie_username和cookie_password
if("cookie_username".equals(cookie.getName())) {
cookie_username=cookie.getValue();
}
if("cookie_password".equals(cookie.getName())){
cookie_password = cookie.getValue();
}
}
}
if(cookie_username!=null&&cookie_password!=null) {
//登录代码
UserService service=new UserService();
User user=null;
try {
user=service.login(cookie_username, cookie_password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//将登录的用户的user对象存到session中
session.setAttribute("user", user);
}
//方行
chain.doFilter(req, resp);
}
4. 案例四:解决全局乱码问题
- 数据库中的用户名是汉字,但是有个问题汉语无法存储到cookie中,因为cookie只能存储字母文字。
- 解决方案,如果是中文,就将中文编码,然后存储,当取值的时候再解码。对中文进行编码,然后取出后再解码。
String username_code=URLEncoder.encode(username,"UTF-8");
- 将编码后的中文存储到cookie中,然后再过滤器中解码,因为过滤器获得cookie后此时是utf-8编码,获得后需要解码再登录,解码的代码:这个是写在过滤器中。
//恢复中文用户名
cookie_username = URLDecoder.decode(cookie_username, "UTF-8");
5. 通过Filter过滤器使用装饰者模式解决post,get提交的乱码问题
- 表单的提交有post和get两种方式,通过装饰者模式解决乱码问题。
第一步: 创建一个Filter类,过滤器,当表单提交Servlet时,过滤器先过滤,如果cookie中有中文信息,可以在过滤器中处理好再放行,这样servlet类就可以直接获取参数,而不是乱码了。
第二步: 装饰者模式的实现原理,1)增强类和被增强的类要实现统一接口。2)在增强类中传入被增强类,3)需要增强的方法重写,不需要增强的方法调用被增强的对象。
public class EncodingFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//在传递request之前对request的getParameter方法进行增强
/*
* 装饰者模式(包装)
* 1、增强类与被增强的类要实现统一接口
* 2、在增强类中传入被增强的类
* 3、需要增强的方法重写 不需要增强的方法调用被增强对象的
*/
//被增强的对象,这里采用了多态形式,因为HttpServletRequest是接口,无法实例化。因此只能是多态。
HttpServletRequest req = (HttpServletRequest) request;
//增强对象,增强类中传入了被增强类
EnhanceRequest enhanceRequest = new EnhanceRequest(req);
chain.doFilter(enhanceRequest, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
class EnhanceRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
public EnhanceRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
//对getParaameter增强
@Override
public String getParameter(String name) {
String parameter = request.getParameter(name);//乱码
try {
parameter = new String(parameter.getBytes("iso8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return parameter;
}
}
- 一个java文件多个类,是可以的。
- EnhanceRequest是增强对象,实现HttpServletRequest。而req采用多态的形式创建的对象,因此实现HttpServletRequest.因此两个对象实现了相同的接口。
- 增强类中传入了被增强类,增强类由于增强了一些方法,再将增强类对象当做请求参数传递,就实现了方法的增强。
- 首先是将请求参数包装到ServletRequest类对象里,这样在Servlet里面就可以通过方法获取参数,而过滤器时将请求对象放到一个更大的请求对象里面,这个更大的请求对象由于对里面的方法做了改变故还可以传递参数,传递参数后就完成了一定的目的。