Servlet高级
一. Cookie
1.Cookie概念
1.1 Cookie是保存在客户端的小文本
保存的位置分两种: 1).Cookie可能保存在客户端浏览器的所占内存中,关闭浏览器后,Cookie就不再存在 2).Cookie也可能保存在客户PC机的硬盘上,设置有效时间,超过有效时间后失效
1.2 Cookie的常见应用
简化登录:很多网站在登录时,可以选择多久之内不需要登录,在选择的时间段内,不用登录即可以到欢迎页面。 记录浏览记录:购物网站,每次登录后,会看到曾经浏览过的商品信息。
1.3 使用Cookie的原则
Cookie能够把小文本保存到客户端,在服务器与客户端进行传输。然而,Cookie容易造成信息泄露,另外,客户端可以通过设置阻止Cookie,也可能手工清除Cookie。 因此,使用Cookie的原则: 1). 不用cookie保存对保密性要求高的信息,例如银行卡密码等 2). 不用cookie实现必要功能,防止cookie被删除后出现错误 3). cookie用来实现“锦上添花”的功能,也就是说,一旦cookie被禁止或者被删除,应用依然能正常运行
2.Cookie类
2.1 创建cookie对象
在Servlet API中,存在类Cookie,可以使用new关键字创建cookie对象 Cookie对象是保存一对键值对,都是字符串形式 Cookie newCookie = new Cookie(“username”, “zhangsan”);
2.2 Cookie类中的方法
类型 | 方法名称 | 说 明 |
---|---|---|
void | setMaxAge(int expiry) | 设置Cookie的有效期,以秒为单位,Cookie保存在硬盘上,否则保存在内存中 |
void | setValue(String value) | 在Cookie创建后,对Cookie进行赋值 |
String | getName() | 获取Cookie的名称 |
String | getValue() | 获取Cookie的值 |
String | getMaxAge() | 获取Cookie的有效时间,以秒为单位 |
3.如何保存及获取Cookie
3.1 保存Cookie
Cookie要保存到客户端,凡是写到客户端的方法,基本都在响应中。 HttpServletResponse中提供了方法,把Cookie保存到客户端 response.addCookie(newCookie)
3.2 获取Cookie
再次访问与保存Cookie相同域名的网站时,HTTP协议将把有效时间内的Cookie都发送到服务器,容器将把Cookie封装到请求中。 HttpServletRequest类提供了获取cookie对象的方法 Cookie[] cookies request.getCookies();
4.使用Cookie实现简化登录
4.1 需求
用户登录时,可以选择长时间内不需要登录
4.2 思路
访问登录页面index.jsp时,获取所有Cookie对象,检查是否存在已经保存的用户名和密码,如果存在,则直接提交到Servlet进行登录处理。如果不存在,则显示index.jsp页面 Servlet中获取用户选择不需要登录的时间,把登录信息保存到cookie中,设置有效时间,写到客户端
4.3 修改index.jsp
<%
String username=null;
String password=null;
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookie cookie:cookies){
if(cookie.getName().equals(“username”)){
username=cookie.getValue();
}
if(cookie.getName().equals(“password”)){
password=cookie.getValue();
}
}
}
if(username!=null&&password!=null){
request.getRequestDispatcher(“LoginServlet? username=”+username+”&pwd=”+password).forward(request, response);
}
%>
4.4 修改LoginServlet
//获得JSP页面的时间信息 String timelength=request.getParameter(“timelength”); int days=0; if(timelength!=null){ days=Integer.parseInt(timelength); } if(days!=0){ Cookie usernamecookie=new Cookie(“username”,username); Cookie passwordcookie=new Cookie(“password”,pwd); usernamecookie.setMaxAge(days243600); passwordcookie.setMaxAge(days243600); response.addCookie(usernamecookie); response.addCookie(passwordcookie); }
二.session会话
1.会话概念
客户端向服务器端发送请求,服务器端接受请求并生成响应返回给客户端,客户端对服务器端这样一次连续的调用过程,被称为会话(session)。 例如:访问12306网站后,用户可以查询车次、登录用户、购票、支付、退票、改签、看新闻….只要这个过程中没有关闭浏览器,同时12306网站服务器也一直正常,就是一次会话。 注意:不同浏览器,不同版本,对会话的支持也有所差别。
2.会话的典型应用
2.1 登录访问控制
某些资源不能直接访问,只对登录用户开放。
2.2 实现方法
把登录后的信息保存到会话中,访问资源前,先查看会话中的登录信息,如果存在,则允许访问,否则跳转到登录页面
2.3 问题
登录信息能否保存到请求中? 不可以,因为请求的有效范围很小,除了请求转发外,都生成新的请求。而会话有效范围大,在一次会话中,服务器端与一个客户端只维护一个会话对象。
3.会话API-HttpSession接口
3.1 HttpSession接口-如何获得该接口类型对象
Servlet API中 定义了HttpSession接口,用来封装会话对象。HttpSession是接口,不能直接用new创建对象,会话对象是容器创建的,使用HttpServletRequest中的方法获得会话对象。 //获取跟当前请求相关的session,如果不存在session,就创建一个新的session对象返回。 public HttpSession getSession()
//如果参数create值为true,与无参的getSession方法等同。如果参数create的值是false,那么如果不存在与当前请求相关的session对象,则返回null,如果存在则直接返回会话对象。 public HttpSession getSession(boolean create) JSP文件中 使用会话对象的方法,由于JSP文件中有内置对象session,可以直接调用HttpSession接口中任意方法。
3.2 HttpSession接口中定义的方法
返回值类型 | 方法名称 | 说 明 |
---|---|---|
void | setAttribute(String key,Object value) | 以key/value的形式保存对象值 |
Object | getAttribute(String key) | 通过key获取对象值 |
void | removeAttribute(String key) | 通过key删除属性 |
int | getMaxInactiveInterval() | 获取session的有效非活动时间,以秒为单位 |
void | setMaxInactiveInterval (int interval ) | 设置session的最大非活动时间,以秒为单位,超时将被销毁。 |
String | getId() | 获取session对象的编号 |
void | invalidate() | 设置session对象失效 |
boolean | isNew() | 判断一个session是不是一个新创建的会话对象 |
3.3 HttpSession中与属性有关的方法
HttpSession接口中定义了三个与属性有关的方法,包括setAttribute以及getAttribute、removeAttribute,分别用来存属性、取属性、删除属性。 这三个方法的声明与HttpServletRequest种的与属性相关方法完全相同。 会话属性与请求属性区别:主要区别是有效范围不同 请求中的属性只在当前的请求对象中有效。只有通过请求转发时,才能把当前请求对象转发到下一个资源,其他情况都生成新的请求,所以请求属性也不再可用 会话属性在会话对象中有效。客户端与服务器连接后,只要没有关闭浏览器,服务器也没有出现异常,就是一次会话,会话属性就一直有效。 总结:由于会话对象有效时间长,所以安全性相对低,所占资源相对多,因此:请求属性可以解决的问题就用请求,必须用会话的才用会话。
4.案例:使用会话实现访问控制
4.1 LoginServlet
LoginServlet登录成功后,把用户名保存到会话属性中。属性名字是username,值是登录成功的用户名值。 else if(flag==1){ HttpSession session=request.getSession(); session.setAttribute(“username”, username); request.getRequestDispatcher(“loginsuccess.jsp”).forward(request, response); }
4.2 admin.jsp
修改admin.jsp,从会话对象中获取名字是username的属性,如果属性为空,说明没有登录成功,则跳转到index.jsp,并显示提示信息。否则,说明登录成功,显示admin.jsp <% String username=(String)(session.getAttribute(“username”)); if(username==null){ request.setAttribute(“msg”,”该资源必须登录后访问”); request.getRequestDispatcher(“../index.jsp”).forward(request, response); } %> JSP文件中可以直接使用session内置对象,调用HttpSession接口中的任意方法。
5.会话失效
5.1 会话为什么要失效
会话对象是容器创建的,并保存在容器中 如果客户端连接到服务器后,却置之不理,不做任何操作,那么容器维护这些会话对象将占用很多资源。因此,容器都会在默认时间内销毁会话对象,多数容器默认30分钟销毁会话对象。
5.2 容器自动销毁会话对象
多数容器会在会话对象闲置30分钟后自动销毁。所谓闲置,就是没有使用Session对象。Tomcat默认30分钟后销毁。 测试: 1、登录后,访问admin.jsp页面,成功访问 2、修改系统时间,为当前时间的30分钟后 3、再次直接访问admin.jsp,跳转到登录页面,说明会话对象已经被销毁,所以admin.jsp中的会话是新的会话对象,取不到username,因此访问失败
5.3 在web.xml中配置会话失效时间
多数容器会在会话对象闲置30分钟后自动销毁。可以在web.xml中进行配置,修改默认时间。例如,修改为50分钟销毁。 测试: 1、登录后,访问admin.jsp页面,成功访问 2、修改系统时间,为当前时间的30分钟后 3、再次直接访问admin.jsp,依然能够成功访问。 4、修改系统时间,为当前时间的50分钟后,跳转到登录页面,说明50分钟后会话对象已经被销毁,所以admin.jsp中的会话是新的会话对象,取不到username,因此访问失败
5.4 使用setMaxInactiveInterval设置最长有效时间
在web.xml中配置的是该应用下所有会话对象的有效时长,如果需要对特定会话对象设置特定的有效时间,可以使用HttpSession接口中的setMaxInactiveInterval设置,以秒为单位,如果参数是负数,表示永远不失效。例如,在LoginServlet中,将会话的有效时长设置为2小时。 session.setMaxInactiveInterval(2_60_60); 测试:1、登录后,访问admin.jsp页面,成功访问 2、修改系统时间,为当前时间的30分钟后 3、再次直接访问admin.jsp,依然能够成功访问。 4、修改系统时间,为当前时间的2小时后,需要登录访问。 如果用多种方法设置会话的有效时间,以较小时间为准。
5.5 调用invalidate方法使会话失效
除了根据有效时间使会话失效外,还可以调用HttpSession中的invalidate方法,使会话失效。 主要区别: 通过setMaxInactiveInterval,或者web.xml配置,或者容器默认时间,都是根据会话闲置时间,容器自动销毁会话 调用invalidate方法,是立即销毁会话对象
6.使用会话失效实现登出功能
6.1 为什么登出
登出时主要是要把保存登录信息的会话销毁,以保证用户登录信息安全。同时提高服务器端的效率。
6.2 实现
第一步:修改页面 在loginsuccess.jsp和admin.jsp中添加超级链接 登出
第二步:创建LogOffServlet 在LogOffServlet中销毁会话对象,存储提示信息,跳转到index.jsp public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(“utf-8”); HttpSession session=request.getSession(); session.invalidate(); request.setAttribute(“msg”, “已经登出,请重新登录。”); request.getRequestDispatcher(“index.jsp”).forward(request, response); }
7.会话实现机制
会话由谁创建的? 会话由容器创建的。 会话保存在哪里? 会话保存在容器中,有若干客户端与服务器连接,服务器会为每个客户端的一次会话创建一个会话对象,而这些会话对象都 在容器中,如何区分会话对象与客户端的联系? 多数容器都采用cookie机制实现会话机制 结论:多数容器都使用cookie机制实现会话,也就是说使用cookie来保存客户端与服务器里会话对象之间的对应关系。
7.1 使用cookie实现会话机制的过程
1、当容器创建一个新的HttpSession对象后,即生成一个随机数,称为会话ID,并将ID值封装成一个名字为JSESSIONID的cookie,返回给客户端。 2、调用request.getSession方法获得会话对象时,容器先从request中获取JSESSIONID值,根据JSESSIONID值查找到对应的会话对象,返回使用。 3、如果没有获取到JSESSIONID值,认为当前的请求没有相关联的会话对象,重复步骤1
7.2 Cookie被阻止的处理
阻止Cookie后,与会话相关的功能将失效
7.3 阻止Cookie后的处理方法
阻止Cookie后,会话失效的主要原因是:每次调用getSession方法,首先是查找名字是JSESSIONID的cookie,如果没有,则创建新的会话对象。当cookie被阻止,每次都找不到JSESSIONID名字的cookie,所以每次都创建新的会话,因此都认为没有登录。
解决办法:强制把JSESSIONID传递给相关资源即可
如果Cookie被阻止,可以使用URL重写方法,强制把名字为JSESSIONID的Cookie的值添加到URL,该方法在loginsuccess.jsp中,HttpServletResponse定义:
>访问admin.jsp页面
可见:jsessionid值强制添加到URL,因此不会每次都创建新的会话对象
8.Cookie与Session的区别
1.session是在服务器端保存用户信息,Cookie是在客户端保存用户信息 2.session中保存的是任意对象,Cookie保存的是字符串 3.session随会话结束而关闭,Cookie可以长期保存在客户端硬盘上,也可以临时保存在浏览器内存中 4.Cookie通常用于保存不重要的用户信息,重要的信息使用session保存
三.上下文
1.上下文的概念
每一个Web Project,运行时都部署在Tomcat下,称为一个应用。部署后,启动Tomcat时,Tomcat将为每一个应用创建一个对象,这个对象称为上下文对象。也就是说,一个应用有且只有一个上下文对象,由容器创建,并保存在容器中。 容器是什么意思? Tomcat 组成如下图: 主要有 Container 和 Connector 以及相关组件构成。 Server:指的就是整个 Tomcat 服 务器,包含多组服务,负责管理和 启动各个 Service,同时监听 8005 端口发过来的 shutdown 命令,用 于关闭整个容器 ; Service:Tomcat 封装的、对外提 供完整的、基于组件的 web 服务, 包含 Connectors、Container 两个 核心组件,以及多个功能组件,各 个 Service 之间是独立的,但是共享 同一 JVM 的资源 ; Connector:Tomcat 与外部世界的连接器,监听固定端口接收外部请求,传递给 Container,并 将 Container 处理的结果返回给外部; Container:Catalina,Servlet 容器,内部有多层容器组成,用于管理 Servlet 生命周期,调用 servlet 相关方法。 Tomca的心脏是两个组件:Connecter和Container。一个Container可以选择多个Connecter,多个Connector和一个Container就形成了一个Service。Service可以对外提供服务,而Server服务器控制整个Tomcat的生命周期。
2.上下文的作用
上下文对象类似一个全局变量,在整个应用中有效;利用上下文对象,可以实现多个用户之间的数据共享。
3.上下文API-ServletContext接口
Servlet API中定义了ServletContext接口,用来封装上下文对象
类型 | 方法名称 | 说 明 |
---|---|---|
void | setAttribute(String key,Object value) | 以key/value的形式保存对象值 |
Object | getAttribute(String key) | 通过key获取对象值 |
String | getInitParameter(String path) | 返回上下文初始化参数的值 |
String | getRealPath(String path) | 根据虚拟路径返回实际路径 |
4.如何获得ServletContext对象
ServletContext是接口,不能直接创建对象。ServletContext对象是容器创建的,可以使用Servlet API中提供的方法获取该对象。 Servlet API中 ServletConfig接口中定义的getServletContext()方法,返回ServletContext对象
Servlet类实现了ServletConfig接口,可直接调用getServletContext()方法,返回ServletContext对象 JSP中 JSP文件的内置对象application即上下文对象,可以调用ServletContext接口中的任意方法
5.使用上下文实现登录人次统计
5.1 需求
登录成功后,人次增1,每次登录成功后,在成功页面success.jsp显示登录人次 请求<会话<上下文。 每次登录的都是新的请求。 每次打开浏览器访问都是新的会话。每个人的浏览器访问都是独立的会话。
5.2 思路
登录人次需要使用变量保存起来,每次登录成功后对该变量加1,并显示
问题:变量保存到哪里呢? 保存到请求中? 不可以,如果保存到请求中,每次登录都是新的请求,那么都会重新计数 保存到会话中? 不可以,如果保存到会话中,不同PC客户端,是不同会话,将重新计数 保存到上下文中? 可以,上下文是一个应该只有一个,所以可以多个用户共享,计数可以累加。 相当于全局变量。
5.3 修改LoginServlet
获取上下文对象,从上下文中取count属性,如果不存在,说明第一次访问,初始化该值为1。如果存在,说明已经有客户端访问过,直接加1即可。把更新过的值保存到上下文中。 ServletContext ctxt=this.getServletContext(); String countstr=(String) ctxt.getAttribute(“count”); int count=0; if(countstr==null){ count=1; }else{ count=Integer.parseInt(countstr); count++; } ctxt.setAttribute(“count”, count);
5.4 修改loginsuccess.jsp
使用JSP的内置对象application,获取属性count,并显示
您是第<%=application.getAttribute(“count”)%>位访问者!
问题:Tomcat重新启动后,计数器将从1开始。因为重新启动容器,上下文对象将被销毁,重新创建,因此存储在上下文中的count也从0开始。后续可以用监听器解决这个问题。
6.上下文参数
6.1 web.xml中配置上下文参数
如果在一个应用中的多个Servlet或JSP中都使用的变量,以后还可能被修改,则可以考虑配置成上下文参数。 在web.xml的下配置:
6.2 如何获得上下文参数
在ServletContext中定义了getInitParameter方法可以获得上下文参数的值
Servlet API 中
ServletContext ctxt=this.getServletContext();
//仅仅测试上下文参数使用,无实际意义
System.out.println(“level: “+ctxt.getInitParameter(“level”));
JSP 中
Level值:<%=application.getInitParameter(“level”)%>
6.3 上下文参数与Servlet参数
1. 配置位置 上下文参数在下使用配置
7.请求、会话、上下文属性
7.1 方法比较
在HttpServletRequest、HttpSession、ServletContext中有三个相同的方法,都与属性有关 1)public void setAttribute(String name, Object value):该方法用来将对象作为属性存储到相应范围中。 2)public Object getAttribute(String name):该方法用来从某范围中获取属性。 3)public void removeAttribute(String name):该方法用来从某范围中删除属性。
7.2 属性比较
请求属性 HttpServletRequest提供了上面提到的三个方法,可以将对象作为属性存储到请求中,可以通过名字获取请求对象中的属性,也可以通过名字删除相应的属性。请求对象的生命周期较短,每个线程访问Web组件,都会创建一个新的请求,只有请求转发时才将请求转发到下一资源。所以请求属性不会长期驻留在容器内存中,也不会带来并发访问的问题,能够使用请求属性完成相关功能时,尽量使用请求属性。 会话属性 HttpSession接口中定义了上面提到的三个方法,可以将对象作为属性存储到会话中,可以通过名字获取会话对象中的属性,也可以通过名字删除相应的属性。会话对象在一次会话过程中是一个唯一的对象,生命周期比请求要长。建议在Web应用中,只有当某些对象必须在会话范围内共享,必须使用会话属性时,才考虑使用会话属性。 上下文属性 ServletContext接口提供了上面提到的三个方法,可以将对象作为属性存储到上下文中,可以通过名字获取上下文对象中的属性,也可以通过名字删除相应的属性。上下文对象随着容器启动而创建,只有容器关闭时方销毁,所以生命周期很长。而且一个应用只有一个唯一的上下文对象,因此,不要轻易使用上下文属性,只有当确定某对象必须在上下文范围内共享时,才考虑使用上下文属性。
四.监听器
1. 事件
1.1 事件概念
监听器是为了监听事件并处理的,所以要理解监听器的概念,首先要理解事件的概念。 某些操作总会触发一种事件发生,如启动或关闭容器、创建或销毁会话等。当发生了某种事件,容器将创建对应的事件类对象。也就是说,API中已经定义好了事件的类型,容器进行了实现,当某些特定操作发生时,会自动触发相应的事件。
1.2 事件类型
Servlet API中定义了6种事件类型 ServletContextEvent:该类表示上下文事件,当应用上下文对象发生改变,如创建或销毁上下文对象时,将触发上下文事件。 ServletContextAttributeEvent:该类表示上下文属性事件,当应用上下文的属性改变,如增加、删除、覆盖上下文中的属性时,将触发上下文属性事件。 ServletRequestEvent:该类表示请求事件,当请求对象发生改变,如创建或销毁请求对象时,触发请求事件。 ServletRequestAttributeEvent:该类表示请求属性事件,当请求中的属性改变,如增加、删除、覆盖请求中的属性时,触发请求属性事件。
HttpSessionEvent:该类表示会话事件,当会话对象发生改变,如创建或销毁会话对象,活化或钝化会话对象时,将触发会话事件。 HttpSessionBindingEvent:该类表示会话绑定事件,当会话中的属性发生变化时,如增加、删除、覆盖会话中的属性时,将触发会话绑定事件。
1.3 监听器接口
Servlet API中定义了8种监听器接口,用来监听不同的事件类型 ServletContextListener:上下文监听器,监听ServletContextEvent事件。 ServletContextAttributeListener:上下文属性监听器,用来监听ServletContextAttributeEvent事件。 ServletRequestListener:请求监听器,监听ServletRequestEvent事件。 ServletRequestAttributeListener:请求属性监听器,用来监听ServletRequestAttributeEvent事件。 HttpSessionListener:会话监听器,监听HttpSessionEvent。
HttpSessionActivationListener:会话活化监听器,监听HttpSessionEvent事件。 HttpSessionAttributeListener:会话属性监听器,监听HttpSessionAttributeEvent事件。 HttpSessionBindingListener:会话绑定监听器,监听HttpSessionAttributeEvent事件。
1.4 事件与监听器的关系
事件对象是容器创建的,触发的条件也已经定义好。例如,只要容器关闭,启动,就会触发ServletContextEvent ,容器会创建该类型对象。 当事件发生后,容器会寻找监听器来处理该事件。监听器需要程序员自定义并配置,然而监听器的类型已经定义好。例如,当发生了ServletContextEvent事件后,只能用ServletContextListener监听器监听。
2. 使用监听器修改登录计数器
2.1 需求
计数器的问题:计数器直接存储在上下文对象中,所以容器重启,或应用重新部署后,上下文对象将重新创建,所以计数从1开始。 修改目标:使用数据库存储计数器的数值,当容器关闭时,把当前的数值保存到数据库中;当容器启动时,从数据库中读取数值。
2.2 思路
容器何时启动或关闭是不确定的,但是只要容器关闭或启动,都会自动触发ServletContextEvent事件,只要能处理这个事件即可。 处理该事件的接口已经定义,是ServletContextListener 因此只要编写上下文监听器,就可以实现。
2.3 实现
创建监听器类 VisitListener VisitListener类实现接口ServletContextListener,其中有两个方法: contextInitialized方法在上下文初始化时自动调用;从数据库中读取数值,把其中内容存储在上下文属性中。 contextDestroyed方法在上下文被销毁时自动调用;读取上下文中的count属性,保存到数据库中。 配置监听器 方式一:注解 @WebListener 方式二:web.xml
五.过滤器
1. 过滤器的概念和作用
问题: 目前的实现方案中,需要在每一个需要访问控制的文件中加上判断代码,代码将很冗余,如果需要修改,也比较繁琐。 除了访问控制这样的功能外,Web应用中还会有其他这种需求,例如权限校验、加密处理、编码集处理等,都需要在若干个文件中编写类似的代码。 解决: 通过过滤器来解决这个问题,可以用来进行通用处理,而不需要在多个文件中写相同代码。
2. 过滤器相关的API
Servlet API 中,与过滤器有关的API共有三个接口,分别是 Filter FilterChain FilterConfig
2.1 Filter接口
Filter接口是过滤器类必须实现的接口,该接口中有三个方法。 //该方法是对filter对象进行初始化的方法,仅在容器初始化filter对象结束后被调用一次。参数FilterConfig可以获得filter的初始化参数 init(FilterConfig filterConfig)
//该方法是filter进行过滤操作的方法,是最重要的方法。过滤器实现类必须实现该方法。方法体中可以对request和response进行预处理。其中FilterChain可以将处理后的request和response对象传递到过滤链上的下一个资源 doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
//该方法在容器销毁过滤器对象前被调用 destroy()
2.2 FilterChain接口
该接口类型作为Filter接口中doFilter方法的参数使用。 FilterChain接口中有一个方法: //该方法可以将当前的请求和响应传递到过滤链上的下一个资源,可能是下一个过滤器,也可能是目标资源。 doFilter(ServletRequest request,ServletResponse response)
2.3 FilterConfig接口
该接口类型作为Filter接口中的init方法的参数使用。 FilterConfig接口中有一个常用方法: //该方法用来获得过滤器的初始化参数值 getInitParameter(String name) 在web.xml中,可以为每一个filter配置需要的初始化参数,与Servlet的类似。过滤器的初始化参数即可通过FilterConfig中的getInitParameter方法获取。 也可以通过注解的方式配置: @WebFilter( filterName=”a1”, urlPatterns= {“/*”}, initParams = { @WebInitParam(name=”encode”,value=”utf-8”) })
3. 过滤器实现访问控制
3.1 在admin下创建其他JSP
为了演示效果,说明问题,在admin目录下创建其他两个JSP文件,目前admin下共三个JSP文件,都需要登录后才能访问。在loginsuccess.jsp页面,添加超级链接,访问这三个页面。
>访问admin.jsp页面
>访问查看员工列表页面
>访问查看个人信息页面
3.2 过滤器LoginFilter
写一个类LoginFiter,实现Filter接口,注意是java.servlet包中的Filter接口。覆盖接口中的三个方法,主要方法是doFilter方法。 public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)arg0; HttpSession session=request.getSession(); String username=(String) session.getAttribute(“username”); if(username==null){ request.setAttribute(“msg”, “请先登录。”); request.getRequestDispatcher(“../index.jsp”).forward(arg0, arg1); } arg2.doFilter(arg0, arg1); } 注意:参数arg0,arg1是ServletRequest,ServletResponse类型,常常需要转换成HttpServletRequest,HttpServletResponse类型。 FilterChain的doFilter方法总被调用,用来把请求和响应按照过滤链传递下去,过滤链由若干个过滤器以及最终的目标资源组成。
3.3 配置过滤器
过滤器要生效,必须在web.xml中配置或者注解配置 web.xml中主要配置以及:
3.4 过滤器配置信息
web.xml中
4. 使用过滤器初始化参数
4.1 配置过滤器初始化参数
和Servlet类似,过滤器也可以配置初始化参数,过滤器的初始化参数,只能在当前过滤器中使用 web.xml中:
4.2 如何获得初始化参数
过滤器的初始化参数,使用FilterConfig接口的getInitParameter方法获得。FilterConfig对象是过滤器类init方法的参数,因此,往往在过滤器类的init方法中获得过滤器参数。 public class LoginFilter implements Filter { private int start; private int end;
public void init(FilterConfig arg0) throws ServletException {
start=Integer.parseInt(arg0.getInitParameter("start"));
end=Integer.parseInt(arg0.getInitParameter("end"));
}
}
4.3 使用初始化参数
获得初始化参数后,可以在需要的时候使用。例如,在doFilter方法中,根据当前时间判断是否需要访问控制。 public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
Timestamp now=new Timestamp(System.currentTimeMillis()); int nowhour=now.getHours();
if(nowhour>start&&nowhour<end){ HttpServletRequest request=(HttpServletRequest)arg0; HttpSession session=request.getSession(); String username=(String) session.getAttribute(“username”); if(username==null){ request.setAttribute(“msg”, “请先登录。”); request.getRequestDispatcher(“../index.jsp”).forward(arg0, arg1); } } arg2.doFilter(arg0, arg1); }
5. 使用过滤器处理中文
5.1 有以下几个方面处理中文
1.JSP文件中,使用指令制定编码格式,指令在后续学习:
<%@ page language=”java” import=”java.util.*” pageEncoding=”utf-8”%>
2.Servlet文件中:
response.setContentType(“text/html;charset=utf-8”);
request.setCharacterEncoding(“utf-8”);
3.JDBC连接串
jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8
4.Tomcat的conf/server.xml
5.2 使用过滤器处理请求编码
上一页的中文处理方法中,其中对request设置编码格式可以使用过滤器实现,创建CharacterFilter并配置使用。 public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)arg0; request.setCharacterEncoding(“utf-8”); arg2.doFilter(arg0, arg1); }
6. 过滤器总结
过滤器用来实现通用的功能,减少代码冗余,提高可维护性 一个过滤器可以配置给多个资源使用 一个资源也可以配置多个过滤器,按照配置顺序调用