[Servlet] 18 过滤器(Filter)


prtyaa
prtyaa 2023-12-27 15:25:35 54364
分类专栏: 资讯

开篇例子帮助学习

我们的朋友小猪喜欢在家里做运动,但是怕不安全,因为谁都可以靠近他家,在奋发图强后有了钱,住进了豪宅,为了运动安全就雇佣了保安,起初这个保安是只负责他家,拦截指Servlet的请求:/pigHome.com,随着时间变的久远,他家所在的这栋楼的很多邻居也觉得在家做运动的时候不安全,就和小猪说,能不能一起出钱再请一个,专门拦住楼下进来的闲杂人等,比如记者朋友,然后就用了拦截部分Servlet的请求: *.com,只要是身上有.com的业主都审查一下,再放行,别的没有的人,休想靠近这些个爱运动的群体,随着运动人数的增多和知名度的打响之后,整个社区的居民都觉得这招好使,但成本略高,毕竟没办法天天做运动所以就想要不在小区门口拦一下也行,这时候就拦截所有:/* 不管谁来,都拦一下,是小区的业主居民就放,不是就死都别想近,最后小猪发现,哇!到他家有 拦截所有保安>拦截部分保安>拦截指定servlet保安来保障自己的隐私和住宅,于是就开始开开心心的邀约其他喜欢做运动的朋友到家里一起做多人运动,因为足够安全

问题:

Servlet 的作用是针对浏览器发起的请求,进行请求的处理。通过 Servlet 技术我们可以灵活的进行请求的处理,但是我们不但要对请求记性处理,我们还需对服务器的资源进行统一的管理 ,比如请求编码格式的统一设置,资源的统一分配等等,这个时候该怎么办呢?

举个例子:

如果说长时间未登录没有了session 或者是盲猜知道了部分功能页面,这个时候对于服务器来说是非常危险的,所以在每次开启新的servlet的时候可以对session进行校验,看看请求是否合法

有个经典的用法是:

到了12点不能在使用网站功能

做权限管理校验:对用户的请求做过滤,过滤通过访问对应的url地址

这里就涉及到RBAC的知识,通俗的说,就是在数据库中设计一张表,表中存放着所有的servlet的url路径.用户登录后,根据UID查询到可以使用的URL存进对应的Session中,在使用中,和过滤器中的做比较,有就可以访问对应的servlet,没有就被拦截

解决:

使用过滤器。

作用:

对服务器资源进行管理校验请求的合法性

保护 servlet

使用:

Filter 接口

Filter 过滤器的配置

案例:

统一管理字符编码

Session 管理


一 创建一个普通java类并实现过滤器接口Filter。

二 需要在web.xml文件内进行配置类似servlet的配置。

	<filter>
		<filter-name>配置的过滤器名称</filter-name>
		<filter-class>要配置的过滤器的全限定路径:包名.类名</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>配置的过滤器名称</filter-name>
		<url-pattern>过滤器拦截请求地址的范围</url-pattern>
	</filter-mapping>
	
	示例:
	    <filter>
               <filter-name>filter</filter-name>
               <filter-class>com.lin.filter.WholeFilter</filter-class>
             </filter>
            <filter-mapping>
                <filter-name>filter</filter-name>
                <url-pattern>/*</url-pattern>
                <!--/* 到服务器的请求都拦截-->
    </filter-mapping>

技能点:

技能点一:过滤器之doFilter方法

作用:

doFilter方法是过滤器的核心方法,服务器在接收到浏览器发过来的请求后,先解析请求信息,创建对象request和response然后根据请求URL地址判断如果符合过滤器的过滤范围,则会调用过滤器中的doFilter 来进行请求拦截,并将request和response对象作为实参传递给doFilter方法。可以在doFilter方法中声明过滤器拦截代码。

服务器在接收到浏览器发过来的请求后,先解析请求信息,创建对象request和response

然后根据请求URL地址判断如果符合过滤器的过滤范围,则会调用过滤器中的doFilter来

进行请求拦截,并将request和response对象作为实参传递给doFilter方法。

我们可以在doFilter方法中声明过滤器拦截代码。

 

参数:

  1. ServletRequest:接收此次拦截的请求的request实参
  2. ServletResponse:接收此次拦截的请求的response实参
  3. FilterChain:可以进行请求放行

3.1chain.doFilter(request, response);

技能点二:过滤器之init和destory方法

init方法:服务器启动时调用

destory方法:服务器关闭时调用

证明:过滤器的生命周期为从服务器开启到服务器关闭

 

技能点三:过滤器之拦截范围配置

拦截所有:

/*

拦截部分Servlet的请求:

*.do(以.do结尾的都拦)

拦截指定Servlet的请求:

和要拦截的指定的Servlet的url-pattern配置完全一致即可,例如:/myFilter

也就是这样

注意:

过滤器之间会出现多重拦截,如果是按照拦截拦截范围的大小在web.xml中自大而小进行的配置则会先执行大范围的拦截器,再执行小范围的拦截器。一般不会使用到3重拦截,除非执行的功能特别重要

拦截所有>拦截部分>拦截指定servlet


使用案例1-请求编码格式

使用过滤器进行统一编码格式

public class MyFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		//设置请求编码格式
		request.setCharacterEncoding("utf-8");
		//设置响应编码格式
		response.setContentType("text/html;charset=utf-8");
		//放行
		chain.doFilter(request, response);
			
	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}
}

案例二 -- session 管理

在过滤器中获取session对象,然后查看session中的数据是否还在如果数据没了,则因为session失效则重定向到登录页面。如果数据还在session没有失效,则放行

public class MyFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		//设置请求编码格式
		request.setCharacterEncoding("utf-8");
		//设置响应编码格式
		response.setContentType("text/html;charset=utf-8");
		//强转request对象
		HttpServletRequest req=((HttpServletRequest)request);
		//强转response对象
		HttpServletResponse resp=((HttpServletResponse)response);
			//判断
				if(obj!=null){
	
			chain.doFilter(request, response);
			}else{
			//重定向到登录页面
			resp.sendRedirect("/project2/login.jsp");
						}
	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}
	
}

上面一波操作时候呢,我们可以发现是存在问题的

问题1:

在过滤器中使用session校验后发现登录页面的访问成了死循环,因为登录页面的请求也就是login.jsp的请求也会被过滤器拦截,而此时session中没有相关数据的造成又重定向到登录页面......

解决1:

对login.jsp和登录请求进行放行(在登录页面销毁session也行)

问题2:

过滤器会拦截所有的请求,包括静态资源(css文件\js文件\image图片)请求也会拦截。

造成页面中的样式和动态效果等出不来

解决2:

对静态资源放行

重点代码对登录页面及执行登录操作的servlet及静态资源放行

if("/project2/login.jsp".equals(uri) || ("/project2/data".equals(uri)&& "userLogin".equals(method)) || uri.startsWith("/project2/css/") || uri.startsWith("/project2/js/")|| uri.startsWith("/project2/images/"))

 

public class MyFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		//设置请求编码格式
		request.setCharacterEncoding("utf-8");
		//设置响应编码格式
		response.setContentType("text/html;charset=utf-8");
		//强转request对象
		HttpServletRequest req=((HttpServletRequest)request);
		//强转response对象
		HttpServletResponse resp=((HttpServletResponse)response);
		//获取此次请求uri
		String uri=req.getRequestURI();
		//获取此次请求的method
		String method=req.getParameter("method");
		//放行登录页面  放行登录请求 放行静态资源
			if("/project2/login.jsp".equals(uri) || ("/project2/data".equals(uri)&& "userLogin".equals(method)) || uri.startsWith("/project2/css/") || uri.startsWith("/project2/js/")|| uri.startsWith("/project2/images/")){
				//放行
				chain.doFilter(request, response);
			}else{
			//session管理(session统一校验)
			//获取Session对象
						HttpSession session = req.getSession();
						Object obj=session.getAttribute("user");
			//判断
			if(obj!=null){
							//获取权限信息
								List<Url> lu=(List<Url>) session.getAttribute("lu");
							//权限校验
								for(Url url:lu){
									if(url.getLocation().equals(method) || url.getLocation().equals(uri)){
										//放行
										chain.doFilter(request, response);
										return;
									}
								}
							//响应
								resp.getWriter().write("power");
								return;
						}else{
							//重定向到登录页面
							resp.sendRedirect("/project2/login.jsp");
						}
			}
	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}
	
}

关于ajax请求的优化,不管是那种方式的请求,是都需要经过过滤器的,之前过滤器中就做了相关的设置,但是长时间内不用页面session就失效了,这时候在重新执行操作的时候,就没有session,也就执行不了操作,所以前台的页面也需要进行优化,删除成功,session没有失效,回到当前页面,session失效后,回到登录页面重新登录获取session


案例三 -- 权限管理

权限管理也是一个很经典的话题,比如QQ音乐,在点击高品质音乐播放时,你购买了会员,你就能听高品质的vip音乐,如果只是普通用户,就告诉你,你需要开个会员,才能听高品质的音乐,这可能就是上流社会的情况吧,说到上流就有这么一波操作

也就是所有的用户都能点按钮,但是能不能实现就看你有没有钞能力了

需求:

不同的用户在对同一功能使用时,有的用户可以直接使用,有的用户会被提示权限不足。

思路:

这里实际上就是运用了RBAC的原理,用户发来发去都是url地址,用户登录的时候从表中查出他能用的rul地址存在session中,那在使用的时候做一下比较就可以了.

1、在数据库中创建一个URL权限表,该表存储了该系统需要被管理的URL。

2、在数据库中创建用户权限中间表,用来进行权限分配

3、在数据库中将权限给用户分配好

4、在用户登录成功后查询该用户具备的URL权限,存储到该用户的session中

5、在过滤器中对当前发起请求的用户的请求地址进行校验,校验该用户是否具备该请求地址权限,如果具备则放行执行,如果不具备则提示权限不足。

数据库设计:

URL权限表:t_url

  1. 编号: urlid
  2. url地址 :location
  3. 描述:remark

用户权限中间表:t_user_url

  1. uid
  2. urlid

SQL语句的设计:查询当前登录用户的url信息

子查询:

select * from t_url where urlid in (select urlid from t_user_url where uid=8)

联合查询:

select * from t_url tu,t_user_url tul where tu.urlid=tul.urlid and tul.uid=8

servlet

/***
 * servlet创建一个,在service方法中动态的调用请求处理方法。
 * 注意:
 * 	请求中需要附带要调用的方法名
 * @author MyPC
 *
 */
public class DataServlet extends BaseServlet {
	
	//查询用户信息
	public void selUserInfo(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
		//获取请求信息
		//处理请求信息
			//创建业务层对象
			UserService us=new UserServiceImpl();
			//调用业务层方法处理请求
			List<User> lu=us.selUserInfoService();
		//响应处理结果
			//将结果存储到request作用域中
			req.setAttribute("lu",lu);
			//请求转发
			req.getRequestDispatcher("/user/userList2.jsp").forward(req, resp);
			return;
	}
	//登录处理方法
	public void userLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException{
		System.out.println("DataServlet.userLogin(开始处理用户登录请求)");
		//获取请求信息
				String uname=req.getParameter("uname");
				String pwd=req.getParameter("pwd");
				//处理请求信息
					System.out.println(uname+":"+pwd);
					//创建业务层对象
					UserService us=new UserServiceImpl();
					User u=us.getUserInfoService(uname,pwd);
					System.out.println("用户登录查询结果为:"+u);
				//响应处理结果
					//创建或者获取session对象
					HttpSession hs=req.getSession();
					if(u!=null){//登录成功
						//查询当前用户的URL权限
						List<Url> lu=us.getUserUrlInfoService(u.getUid());
						//将url权限数据存储到session中
						hs.setAttribute("lu",lu);
						//将用户信息存储到session中
						hs.setAttribute("user",u);
						//重定向到main.jsp
						resp.sendRedirect("/project2/main.jsp");
					}else{//登录失败
						
						//将登录失败的标记添加到session中
						hs.setAttribute("flag", "loginFalse");
						//重定向到login.jsp
						resp.sendRedirect("/project2/login.jsp");
					}
	}
	
}

filter

public class MyFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		//设置请求编码格式
		request.setCharacterEncoding("utf-8");
		//设置响应编码格式
		response.setContentType("text/html;charset=utf-8");
		//强转request对象
		HttpServletRequest req=((HttpServletRequest)request);
		//强转response对象
		HttpServletResponse resp=((HttpServletResponse)response);
		//获取此次请求uri
		String uri=req.getRequestURI();
		//获取此次请求的method
		String method=req.getParameter("method");
		System.out.println("当前请求的uri为:"+uri);
		//放行登录页面  放行登录请求 放行静态资源
			if("/project2/login.jsp".equals(uri) || ("/project2/data".equals(uri)&& "userLogin".equals(method)) || uri.startsWith("/project2/css/") || uri.startsWith("/project2/js/")|| uri.startsWith("/project2/images/")){
				//放行
				chain.doFilter(request, response);
			}else{
	//session管理(session统一校验)
		//获取Session对象
			HttpSession session = req.getSession();
			Object obj=session.getAttribute("user");
		//判断
			if(obj!=null){
				//获取权限信息
					List<Url> lu=(List<Url>) session.getAttribute("lu");
				//权限校验
					for(Url url:lu){
						if(url.getLocation().equals(method) || url.getLocation().equals(uri)){
							//放行
							chain.doFilter(request, response);
							return;
						}
					}
				//响应
//这里是针对ajax的请求情况,实际上还是要响应权限不足的弹框或者是页面提示用户
					resp.getWriter().write("power");
					return;
			}else{
				//重定向到登录页面
				resp.sendRedirect("/project2/login.jsp");
			}
}
	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}
	
}

页面ajax代码更改

function del(uid){
	//判断用户选择是否发起ajax请求进行用户信息删除
	if(confirm("您确定要删除吗?")){
		//发起ajax请求进行用户信息的删除
		$.get("data",{method:"delUserInfo",uid:uid},function(data){
			//判断用户是否是权限不足
			if("power"==data){
				alert("权限不足");
			}else if("true"==data){//判断返回的是否是删除成功的字符串,还是session失效后的登录页面
				if(eval(data)){
					alert("用户删除成功");
					window.location.href="data?method=selUserInfo";
				}
			}else{
				window.top.location.href="login.jsp";
			}
			
		});
	}
}

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=31425
赞同 0
评论 0 条
prtyaaL2
粉丝 1 发表 2553 + 关注 私信
上周热门
如何使用 StarRocks 管理和优化数据湖中的数据?  2973
【软件正版化】软件正版化工作要点  2891
统信UOS试玩黑神话:悟空  2864
信刻光盘安全隔离与信息交换系统  2749
镜舟科技与中启乘数科技达成战略合作,共筑数据服务新生态  1283
grub引导程序无法找到指定设备和分区  1253
华为全联接大会2024丨软通动力分论坛精彩议程抢先看!  170
2024海洋能源产业融合发展论坛暨博览会同期活动-海洋能源与数字化智能化论坛成功举办  169
点击报名 | 京东2025校招进校行程预告  165
华为纯血鸿蒙正式版9月底见!但Mate 70的内情还得接着挖...  162
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

加入交流群

请使用微信扫一扫!