JavaWeb学习笔记十:Filter过滤器学习,实现自动登录业务,通过装饰者模式和过滤器解决乱码问题

1. Filter过滤器学习

1.1. Filter的生命周期

  1. Filter的创建:当启动服务器时Filter过滤器开始创建。
  2. Filter启动销毁时,Filter结束

1.2. 总结Filter的作用

  1. 公共代码抽取
  2. 可以对request和response中的方法进行增强(装饰者模式)
  3. 进行权限控制

过滤器在web工程中的作用

2. 案例一:实现登录功能

  1. 登录功能画图分析

登录业务图解

  1. 给前端页面添加action路径(动态的)。
<form class="form-horizontal" action="${pageContext.request.contextPath }/login" method="post">
  1. 给用户名,密码添加name标签用于web层获取参数
  2. 创建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();
		}
  1. 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>
  1. 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;
}
  1. 修改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. 案例三:实现自动登录功能

  1. 自动登录画图分析

自动登录图解

  1. 设置前端jsp页面,设置value和name用于web层判断是否勾选自动登录
<input type="checkbox" name="autoLogin" value="autoLogin"> 自动登录</input>
  1. 自动登录是要将用户登录信息设置到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);
			}
  1. 下面就要设置过滤器了,创建一个过滤器,当登录时,先查看cookie是否有用户信息,如果有拿出来直接登录。
//由于Cookie属于HttpRequest接口的,因此需要强转
//httpServletRequest是ServletRequest的子类,而Http又丰富了一些方法,因此getCookie()父类没有。
HttpServletRequest req=(HttpServletRequest)request;
HttpServletResponse resp=(HttpServletResponse)response;
HttpSession session=req.getSession();//获取session
  1. 判断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();
				}
			}
		}
  1. 判断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);
		}
  1. 过滤器放行,必须写
chain.doFilter(req, resp);
  1. 配置过滤器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>
  1. 源码
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. 案例四:解决全局乱码问题

  1. 数据库中的用户名是汉字,但是有个问题汉语无法存储到cookie中,因为cookie只能存储字母文字。
  2. 解决方案,如果是中文,就将中文编码,然后存储,当取值的时候再解码。对中文进行编码,然后取出后再解码。
String username_code=URLEncoder.encode(username,"UTF-8");
  1. 将编码后的中文存储到cookie中,然后再过滤器中解码,因为过滤器获得cookie后此时是utf-8编码,获得后需要解码再登录,解码的代码:这个是写在过滤器中。
//恢复中文用户名
cookie_username = URLDecoder.decode(cookie_username, "UTF-8");

5. 通过Filter过滤器使用装饰者模式解决post,get提交的乱码问题

  1. 表单的提交有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里面就可以通过方法获取参数,而过滤器时将请求对象放到一个更大的请求对象里面,这个更大的请求对象由于对里面的方法做了改变故还可以传递参数,传递参数后就完成了一定的目的。
发布了202 篇原创文章 · 获赞 198 · 访问量 15万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览