监听器Listener应用
监听器是指专门用于在其他对象身上发生的事件或者状态改变进行监听和相应处理的对象,当被监听的对象发生变化时立即采取相应的行动
Web监听器定义:
- Servlet规范中定义的一种特殊类
- 用于监听ServletContext、HttpSession、ServletRequest等域对象的创建与销毁事件
- 用于监听ServletContext、HttpSession、ServletRequest域对象的属性attribute修改的事件
- 监听事件的类型是通过类所实现的接口进行区分
- 可以在事件发生前和发生后作出一些必要的处理
application对象创建和销毁的监听
- 一个应用对应一个application对象
- 应用启动后自动创建application对象,关闭应用前自动销毁application对象
1、定义一个类实现ServletContextListener
public class CatalogListener implements ServletContextListener {
//在application对象创建时自动回调执行
public void contextInitialized(ServletContextEvent sce) {
ServletContext application=sce.getServletContext();//获取触发事件执行的事件源
//模拟数据的加载
List<CatalogBean> clist=new ArrayList<>();
for(int i=0;i<5;i++){
CatalogBean tmp=new CatalogBean();
tmp.setId(1L+i);
tmp.setName("name"+i);
clist.add(tmp);
}
application.setAttribute("catalogList",clist);
}
//在application对象销毁时自动回调执行
public void contextDestroyed(ServletContextEvent sce) {
ServletContext application=sce.getServletContext();
application.removeAttribute("catalogList");
}
}
2、在web.xml中进行配置
<listener>
<listener-class>com.yan.listeners.CatalogListener</listener-class>
</listener>
3、当特定事件产生时由服务器自动调用
监听的对象
监听的对象有:ServletContext、HttpSession、ServletRequest分别对应JSP9大内置对象中的application、session和request。用于监听ServletContext、HttpSession、ServletRequest等域对象的创建和销毁事件,监听域对象属性发生修改的事件。监听器对象可以在事件发生前、发生后做一些必要的处理。
- application上下文对象,是由容器创建和初始化的,它的范围是整个的web应用,而且整个web应用中只会有一个 application对象存在,当web服务器关闭时,就会将application对象销毁
- session是一种保存用户上下文信息的机制,它是针对每个会话的,它是放在服务器端,通过SessionId区分的,在浏览器和服务器结束后,都会将session销毁。一个用户对应一个session,当长时间不使用会超时自动销毁
- request对象是当客户端发送请求时,容器就会创建一个ServletRequest对象,来进行封装请求数据,同时会创建一个servletResponse对象来进行封装相应数据,当结束封装请求之后,就会销毁该对象 WEB监听器,就是监听这3个对象的创建、销毁和它们的属性发生的变化
监听事件
事件类型 | 描述 | 接口 |
---|---|---|
ServletContext | 处理Servlet上下文被初始化或者被销毁的事件 | ServletContextListener |
ServletContext | 处理Servlet上下文内的属性被增加、删除或者替换时发生的事件 | ServletContextAttributeListener |
HttpSession | 处理HttpSession被初始化或者被销毁的事件 | HttpSessionListener |
HttpSession | 处理HttpSession被激活或钝化时发生的事件 | HttpSessionActivationListener |
HttpSession | 处理HttpSession内的属性被增加、删除或者替换时发生的事件 | HttpSessionAttributeListener |
HttpSession | 处理对象被绑定或者移出HttpSession发生的事件 | HttpSessionBindingListener |
ServletRequest | 处理ServletRequest请求被初始化或者被销毁的事件 | ServletRequestListener |
ServletRequest | 处理ServletRequest请求内的属性被增加、删除或者替换时发生的事件 | ServletRequestAttributeListener |
监听创建和销毁
ServletContextListener用于监听application对象
主要用途是做一些定时器、加载一些全局属性对象、创建全局的数据库连接、加载一些缓存信息
public interface ServletContextListener extends EventListener {
default public void contextInitialized(ServletContextEvent sce) {}
default public void contextDestroyed(ServletContextEvent sce) {}
}
HttpSessionListener用于监听session对象
该监听器的主要作用是统计在线人数、记录访问日志【在后台统计访问时间、IP信息做一些统计数据】
public interface HttpSessionListener extends EventListener {
default public void sessionCreated(HttpSessionEvent se) {} //考点:方法名称
default public void sessionDestroyed(HttpSessionEvent se) {}
}
ServletRequestListener用于监听request对象
该监听器的主要作用是:读取参数、记录访问历史。
public interface ServletRequestListener extends EventListener {
default public void requestDestroyed(ServletRequestEvent sre) {}
default public void requestInitialized(ServletRequestEvent sre) {}
}
监听attribute的增删改
ServletContexAttributetListener用于监听application对象
public interface ServletContextAttributeListener extends EventListener {
//新增attribute时回调
default public void attributeAdded(ServletContextAttributeEvent event) {}
//删除attribute后回调
default public void attributeRemoved(ServletContextAttributeEvent event) {}
//替换attribute后回调
default public void attributeReplaced(ServletContextAttributeEvent event) {}
}
HttpSessionAttributeListener用于监听session对象
public interface HttpSessionAttributeListener extends EventListener {
default public void attributeAdded(HttpSessionBindingEvent event) {} //事件对象的命名不一致
default public void attributeRemoved(HttpSessionBindingEvent event) {}
default public void attributeReplaced(HttpSessionBindingEvent event) {}
}
ServletRequestAttributeListener用于监听request对象
public interface ServletRequestAttributeListener extends EventListener {
default public void attributeAdded(ServletRequestAttributeEvent srae) {}
default public void attributeRemoved(ServletRequestAttributeEvent srae) {}
default public void attributeReplaced(ServletRequestAttributeEvent srae) {}
}
统计在线人数
- 统计的人数值为了实现跨用户数据共享,所以只能使用application存储
- 通过监听session对象创建和销毁计算在线人数
public class CounterListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) { //创建session对象后给application中存储的计数加1
Long counter=0L;
HttpSession session=se.getSession();
ServletContext application=session.getServletContext();
Object obj=application.getAttribute("counter");
if(obj!=null && obj instanceof Long)
counter=(Long)obj;
counter++;
application.setAttribute("counter",counter);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) { //销毁session对象时给application中存储的计数减1
Long counter=0L;
HttpSession session=se.getSession();
ServletContext application=session.getServletContext();
Object obj=application.getAttribute("counter");
if(obj!=null && obj instanceof Long)
counter=(Long)obj;
counter--;
if(counter<0)
counter=0L;
application.setAttribute("counter",counter);
}
}
配置 web.xml
<listener>
<listener-class>com.yan.listeners.CounterListener</listener-class>
</listener>
在页面上获取计数值
${applicationScope.counter}
练习: 统计网站从发布之日起的访问人数
- 不是点击量
- 要求可以配置初始值
- 要求关闭服务器时记录累加值
public class CounterListener implements HttpSessionListener, ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext application=sce.getServletContext();
InputStream is=application.getResourceAsStream("counter.data"); //读取数据文件
DataInputStream dis=new DataInputStream(is);
Long l2=null;
try {
l2 = dis.readLong();
} catch (Exception e){
l2=0L;
}
String ss=application.getInitParameter("counter"); //读取上下文参数
Long l1=null;
try{
l1=Long.parseLong(ss);
} catch (Exception e){
l1=0L;
}
Long counter=Math.max(l1,l2);
application.setAttribute("counter",counter);
}
//线程可能不安全,但是使用同步处理会影响并发性
public void sessionCreated(HttpSessionEvent se) {
Long counter=0L;
HttpSession session=se.getSession();
ServletContext application=session.getServletContext();
Object obj=application.getAttribute("counter");
if(obj!=null && obj instanceof Long)
counter=(Long)obj;
counter++;
application.setAttribute("counter",counter);
}
//线程安全
public void contextDestroyed(ServletContextEvent sce) {
ServletContext application=sce.getServletContext();
Long counter=0L;
Object obj=application.getAttribute("counter");
if(obj!=null && obj instanceof Long)
counter=(Long)obj;
String ss=application.getRealPath(""); //获取应用部署后的根路径
File ff=new File(ss,"counter.data");
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(ff))){
dos.writeLong(counter);
}catch (Exception e){
application.log(e.getMessage());
}
}
}
web监听器用途:
-
统计在线人数和在线用户
登录成功的时候 session.setAttribute(“user”,user);
public class UserListener implements HttpSessionAttributeListener{ @Override public void attributeAdded(HttpSessionBindingEvent event) { String name=event.getName(); Object obj=event.getValue(); System.out.println("name:"+name+",value:"+obj); if("user".equals(name)) { HttpSession session = event.getSession(); ServletContext application = session.getServletContext(); Set<UserBean> userSet = new HashSet<>(); Object obj2 = application.getAttribute("userset"); if (obj2 != null && obj2 instanceof Set) userSet = (Set<UserBean>) obj2; userSet.add(obj); application.setAttribute("userset", userSet); } }
-
系统启动时加载初始化信息
-
统计网站访问量
-
和Spring整合
监听器的启动顺序:
- 在一个web.xml中可以注册多个Servlet监听器,监听器的加载顺序是按照web.xml文件中的顺序加载的
- 如果在web.xml文件中同时配置了监听器、过滤器和Servlet,那么它们的优先级是:
- 监听器>过滤器>Servlet
HttpSession的特殊操作
一般情况下session是保存在服务器内存的,服务器为每一个在线用户保存session对象,当在线用户很多时,session内存的开销将是非常巨大的——直接导致web服务器性能的降低。session的钝化机制就是将不经常使用的session对象序列化存储到文件系统或者是数据库中。需要使用这些session的时候进行反序列化到内存中。整个过程由服务器自动完成
session钝化机制一般是由容器提供的SessionManger管理
-
Tomcat针对session的管理默认采用LRU策略,最近最少使用原则,
-
当Tomcat服务器被关闭或重启时,Tomcat服务器会将当前内存中的Session对象钝化到服务器的文件系统中
-
Web应用程序被重新加载(修改了web.xml)时,内存中的Session对象也会被钝化到服务器的文件系统中
-
可以配置主流内存的Session对象数目,将不常使用的session对象保存到文件系统或者数据库,用的时候重新加载。
-
钝化后的文件的位置:Tomcat安装路径/work/Catalina/hostname/applicationname/SESSIONS.ser
//具体session的激活和钝化是由服务器负责实现的,具体的实现方法是采用对象流,所以要求存储在session中的数据必须实现了Serializable接口
public interface HttpSessionActivationListener extends EventListener {
default public void sessionWillPassivate(HttpSessionEvent se) {}//钝化前执行的操作,可以关闭一些不能钝化的内容
default public void sessionDidActivate(HttpSessionEvent se) {} //激活后执行的操作,可以用于执行一些恢复操作
}
在Servlet规范中提供了两个接口HttpSessionBindingListener和HttpSessionActivationListener分别对应绑定-解除绑定方法和钝化-活化方法。这两个监听器不需要在web.xml中注册。
public class User implements HttpSessionBindingListener {
private String username;
private String password;
public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("绑定,属性名:"+ httpSessionBindingEvent.getName());
}
public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("解除绑定,属性名:"+ httpSessionBindingEvent.getName());
}
}
过滤器
WEB过滤器是一个服务器端的组件,它可以截取用户端的请求与相应信息,并对这些信息过滤
针对IP地址进行过滤
request.getRemoteAddr():String 获取客户端的IP地址
hello filter
1、定义类实现Filter接口
public class HelloFilter implements Filter {
//3生命周期
//filterConfig是当前Filter的配置
public void init(FilterConfig filterConfig) throws ServletException {
//当前Filter的配置信息
String ss=filterConfig.getInitParameter("name");
System.out.println(ss);
//应用上下文的配置信息
ServletContext application=filterConfig.getServletContext();
ss=application.getInitParameter("age");
System.out.println(ss);
}
//request封装当前用户的请求数据
//response封装用户的响应信息
//过滤链chain,提供了方法doFilter表示继续向后执行,至于执行的是目标还是下一个过滤器不确定
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("filter....");
//在doFilter执行之前的处理就是前置处理
System.out.println(request.getRemoteAddr());//客户端IP地址
chain.doFilter(request,response); //继续执行下一个组件,是过滤器还是目标地址不确定
//后置处理
}
//销毁当前Filter对象前执行的方法,一般用于资源的释放
public void destroy() {
}
}
2、在web.xml核心配置文件配置过滤器,所谓的配置是指当过滤器和一个条件建立连接,当访问特定路径时执行过滤器
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.yan.filters.HelloFilter</filter-class>
<init-param> 当前filter的配置参数
<param-name>name</param-name>
<param-value>yanjun</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>*.jsp</url-pattern> 这里实际不是一个路径,而是一个条件。表示所有后缀为.jsp的请求都需要经过过滤处理
</filter-mapping>
黑名单的实现
public class HelloFilter implements Filter {
private String blackList=null;
public void init(FilterConfig filterConfig) throws ServletException {
String ss=filterConfig.getInitParameter("blackList");
if(ss!=null && ss.trim().length()>0)
blackList=ss.trim();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String ss=request.getRemoteAddr();
if(ss!=null && ss.trim().length()>0){
if(blackList!=null){
int pos=blackList.indexOf(ss.trim());
if(pos>-1){
response.setContentType("text/html;charset=utf-8");
PrintWriter out= response.getWriter();
out.println("<h3>fuck you!</h3>");
out.flush();
out.close();
return;
}
}
}
chain.doFilter(request,response);
}
//销毁当前Filter对象前执行的方法,一般用于资源的释放
public void destroy() {
}
}
优化的前提是寻找优化目标点和对应的优化目标
- 记录每个请求URL执行所用时间,以确定优化目标
public class TimerFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest hsr=(HttpServletRequest) request;
long start=System.currentTimeMillis(); 前置处理
chain.doFilter(request, response); //访问目标地址,目标地址响应执行完毕,则返回这里
long end=System.currentTimeMillis(); 后置处理
String url=hsr.getRequestURL().toString();
System.out.println("timer--->"+url+"\t"+(end-start)+"ms");
hsr.getServletContext().log("timer--->"+url+"\t"+(end-start)+"ms");
}
}
<filter>
<filter-name>TimerFilter</filter-name>
<filter-class>com.yan.filters.TimerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TimerFilter</filter-name>
<url-pattern>/*</url-pattern> *表示任意长度的任意字符
</filter-mapping>
基础概念
过滤器链: 针对同一个用户请求url-pattern,与之匹配的过滤器有多个,这个时候用户请求就会依次通过各个过滤器到达web资源。
Filter原理
在没有Web过滤器的情况下,用户直接访问服务器上的Web资源。但是如果存在过滤器,用户就不可以直接访问过滤器了。
Web容器启动的时候过滤器就已经启动了,用户的请求到达过滤器,过滤器判断用户的请求是否符合过滤规则,如果符合规则则将用户的请求发送给Web资源,Web资源将响应信息发送给过滤器,过滤器将Web资源的响应发送给用户
Filter声明周期
实例化方法在Web容器开始装载的时候就执行,初始化方法配置一些初始化参数,Web容器卸载(服务器关闭)的时候执行销毁方法。过滤方法会执行多次,其他方法只会执行一次
过滤接口的定义
实现javax.servlet.Filter接口。需要实现该接口中的3个方法
- init(FilterConfig ):过滤器的初始化方法,Web容器创建过滤器之后将调用这个方法,在这个方法中可以读取web.xml中的过滤器参数
- doFilter(ServletRequest,ServletResponse,FilterChain):完成实际的过滤操作,是过滤器的核心方法。当用户请求访问与过滤器相关联的URL的时候,Web容器将先调用过滤器的doFilter方法。FilterChain参数可以调用chain.doFilter方法【放行方法】,将请求传送给下一个过滤器(或者目标资源),或利用转发、重定向将请求转发给其他资源
- destroy():Web容器在销毁过滤器实例前调用该方法,在这个方法中可以释放过滤器占用的资源。【大多数情况下用不到】
在Servlet容器装载的时候,执行过滤器的init方法,当用户请求页面的时候首先执行doFilter()方法,当Servlet容器卸载的时候执行过滤器的销毁方法。【注意:用户的请求先是到达过滤器并不是直接访问的Web资源】
还有一点需要注意:用户虽然能够改变用户请求的资源(例如:网上购物的时候点击“立即购买”,这个请求先要到达过滤器,如果过滤器检测到用户没有登录,就会将页面重定向到登陆页),但是过滤器不能直接处理用户的请求(过滤器不是Servlet),不能直接返回数据。
过滤链执行流程
![过滤链执行流程](images/过滤链执行流程.png)
过滤器实际应用
通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:
-
通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源
比如可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。
-
通过在调用chain.doFilter方法之前,做些处理来达到某些目的
比如解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。
-
通过在调用chain.doFilter方法之后,做些处理来达到某些目的
比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。
用户身份的验证
例如现在有一个web项目,登陆页login.jsp将用户名和密码提交给LoginServlet处理,Servlet使用request.getParameter方法获得表单中的用户名和密码,将用户名和密码进行验证,验证成功则页面重定向到success.jsp,显示登陆成功和登录的用户名【保存在session中再从session中取出】;如果登录失败则重定向到failure.jsp。
在不使用过滤器的情况下,即使用户不进行登录也可以访问到success.jsp——任何人都可以访问到success.jsp,这显然来说不安全
编码转换
解决POST请求参数和响应输出的中文乱码
public class SetCharacterEncodingFilter implements Filter {
private String encoding; //编码可以通过<init-param>元素配置
public void init(FilterConfig filterConfig) throws ServletException {
encoding = filterConfig.getInitParameter("encoding");
if(encoding == null){//如果用户忘记配置,默认encoding为UTF-8
encoding = "UTF-8";
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//只能解决POST请求参数乱码问题
request.setCharacterEncoding(encoding);
//指定输出编码(最后带上,后面会有说明)
response.setCharacterEncoding(encoding);
//指定输出流编码及客户端应使用的码表
response.setContentType("text/html;charset="+encoding);
chain.doFilter(request, response);
}
public void destroy() { }
}
配置web.xml
<filter>
<filter-name>SetCharacterEncodingFilter</filter-name>
<filter-class>com.yan.filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SetCharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern> 过滤当前应用中的所有请求
</filter-mapping>
禁止客户端缓存动态资源
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
//响应头为HTTP协议里的,需转换一下
HttpServletRequest request = null;
HttpServletResponse response = null;
try{
request = (HttpServletRequest)req;
response = (HttpServletResponse)resp;
}catch(Exception e){
throw new RuntimeException("not-http request or response");
}
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "no-cache"); //
response.setHeader("Pragma", "no-cache"); //这三个参数的意义差不多
chain.doFilter(request, response);
}
web.xml配置
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>com.yan.filters.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>/servlet/*</url-pattern> 针对所有/servlet/目录下的请求进行拦截
<url-pattern>*.jsp</url-pattern> 针对所有的.jsp请求进行拦截处理
</filter-mapping>
控制静态资源缓存时间
public class SetCacheExpiresFilter implements Filter {
private int htmlExp;//HTML的缓存时间,单位为小时,下同
private int cssExp;//CSS的缓存时间
private int jsExp;//JS的缓存时间
public void init(FilterConfig filterConfig) throws ServletException {
htmlExp = Integer.parseInt(filterConfig.getInitParameter("html"));
cssExp = Integer.parseInt(filterConfig.getInitParameter("css"));
jsExp = Integer.parseInt(filterConfig.getInitParameter("js"));
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
// 响应头为HTTP协议里的,需转换一下
HttpServletRequest request = null;
HttpServletResponse response = null;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) resp;
} catch (Exception e) {
throw new RuntimeException("not-http request or response");
}
//根据请求资源的后缀名确定缓存时间
String uri = request.getRequestURI();
String extName = uri.substring(uri.lastIndexOf(".")+1);
long expTime = 0;
if("html".equals(extName)){
expTime = System.currentTimeMillis()+htmlExp*60*60*1000;
}else if("css".equals(extName)){
expTime = System.currentTimeMillis()+cssExp*60*60*1000;
}else if("js".equals(extName)){
expTime = System.currentTimeMillis()+jsExp*60*60*1000;
}
response.setDateHeader("Expires", expTime);
chain.doFilter(request, response);
}
public void destroy() { }
}
web.xml配置
<filter>
<filter-name>SetCacheExpiresFilter</filter-name>
<filter-class>com.yan.filters.SetCacheExpiresFilter</filter-class>
<init-param>
<param-name>html</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>css</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>js</param-name>
<param-value>3</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SetCacheExpiresFilter</filter-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.js</url-pattern>
</filter-mapping>
用户自动登录
当用户登陆时,将表单提交到LoginServlet处理,如果用户勾选了记住我,则将用户的登陆信息存入Cookie:Cookie名为“logInfo”,值为(用户名的base64加密结果_密码的md5加密结果)
public class AutoLoginFilter implements Filter {
//表现层同service层打交道
private UserService service = new UserServiceImpl();
public void init(FilterConfig filterConfig) throws ServletException { }
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
// 转为Http协议的request和response
HttpServletRequest request = null;
HttpServletResponse response = null;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) resp;
} catch (Exception e) {
throw new RuntimeException("not-http request or response");
}
HttpSession session = request.getSession();
// 判断用户有没有登录:只管没有登录的
User sUser = (User) session.getAttribute("user");
if (sUser == null) {
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
Cookie cookie = cookies[i];
//名为logInfo的Cookie记录了登录信息(用户名、密码)
if ("logInfo".equals(cookie.getName())) {
String value = cookie.getValue();
//Cookie中的用户名是经过Base64加密的,所以需要解密
String username = SecurityUtil.base64Decode(value.split("_")[0]);
String password = value.split("_")[1];
//Cookie中的密码是md5加密后的,所以第三个参数为true
User user = service.login(username, password, true); //通过则在session中设置登陆标记
if(user!=null) session.setAttribute("user", user); break;
}
}
}
chain.doFilter(request, response);
}
public void destroy() { }
}
迭代
JSTL
为了避免在jsp页面中使用java脚本,以方便分工合作开发
添加依赖,在目前tomcat中并没有包含jstl标签库jar
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
引入标签库
<%@ taglib uri="tld中的URI配置" prefix="tld文件种的short-name配置" %>
核心标签库
引入核心标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
c:if用于执行条件判断
c:forEach用于执行foreach循环
<c:if test="${not empty applicationScope.catalogList}">
<c:forEach var="catalog" items="${applicationScope.catalogList}">
${catalog.id}---${catalog.name}<br/>
</c:forEach>
</c:if>