过滤器(Filter)和监听器(Listener)
原创    loonbs    发表于:2017-07-20 22:55:46
  阅读 :41   收藏   编辑

一、过滤器

Filter(过滤器)并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

过滤器在执行过程中任何时候都可以打断,只要不执chain.doFilter()方法就不会再执行后面的过滤器和请求的内容。因此,要特别注意过滤链的执行顺序问题。假如在逻辑出现两次doFilter会导致有些页面会执行两次。

(一)Filter开发步骤

1、编写java类实现Filter接口,并重写其方法

例如:字符编码的 Filter

package filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
 * Description:
 * 设置编码格式的filter
 * @author lee
 */
public class ContentType implements Filter{
    private String charset;
    private boolean enabled;

    @Override
    public void destroy() {}

    /**
     * Description:
     * 设置编码格式
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        //设置编码格式
        if(enabled && charset!=null)
            resp.setCharacterEncoding(charset);

        //执行doFilter方法,放行,进入目标资源或下一个过滤器
        chain.doFilter(req, resp);
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
        charset = config.getInitParameter("charset");
        enabled = "ture".equals(config.getInitParameter("enabled"));
    }
}

2、在 web.xml 文件中使用和元素对过滤器进行注册,并指定拦截资源。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
            id="WebApp_ID" 
            version="3.1">
  <display-name>web</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

  <!-- 注册监听器 -->

  <filter>
    <!-- 监听器名称 -->
    <filter-name>charset</filter-name>
    <!-- 监听器的class全称,包名+类名 -->
    <filter-class>filter.ContentType</filter-class>
    <!-- 初始化参数 -->
    <init-param>
        <param-name>charset</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <init-param>
        <param-name>enabled</param-name>
        <param-value>true</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>charset</filter-name>
    <!-- 
    设置 filter 所拦截的请求路径(过滤器关联的URL样式)
    值要与浏览器输入的地址相匹配,通过url-pattern查找指定的资源
    写法:
    1.完全匹配  要求以/开始,名称与url一致.
    2.使用通配符 *
    1.目录匹配   以/开始,以*结束.
    2.扩展名匹配 不能以/开始,以*.xxx对束
    (目录匹配和扩展名匹配不能同时使用,例如 /*.jsp) 
    -->
    <!-- /*意味着拦截所有资源 -->
    <url-pattern>/*</url-pattern>

    <!-- 根据servlet的内部名称拦截,拦截名内部名称为Servlet的servlet -->
    <servlet-name>Servlet</servlet-name>

    <!-- 
    指定过滤器所拦截的资源被 Servlet 容器调用的方式。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
    REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
    INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
    FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
    ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用 
    -->
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>

</web-app>

Filter链
多个Filter的访问先后顺序由 配置在前面的Filter 执行要早于配置在后面的Filter决定 。
(关于在 元素中,的匹配方式可以参考另外一篇博客Servlet编程基础 中的映射路径)

这里也可以通过注解在注册过滤器,例如

@WebFilter(filterName="过滤器名称",urlPattern="需要进行过滤的url")
(二)Filter的生命周期

过滤器是服务器启动的时候创建和初始化,当有请求访问时就会调用过滤器的doFilter方法,当关闭服务器的时候就会调用destroy方法销毁过滤器。

public void init(FilterConfig filterConfig) throws ServletException;
//1、Filter的创建和销毁由WEB服务器负责。web应用程序启动时创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
//2、当客户请求访问与过滤器关联的URL的时候,将先执行doFilter方法。

public void destroy();//销毁
//3、Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁。
(三)FilterConfig对象

在web.xml配置文件可以为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,初始化参数。
例如在web.xml文件中,配置filter初始化参数:

<!-- 部分代码 -->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
            id="WebApp_ID" 
            version="3.1">
  <display-name>web</display-name>

  <filter>
    <filter-name>charset</filter-name>
    <filter-class>filter.ContentType</filter-class>
    <!-- 初始化参数 -->
    <init-param>
        <param-name>name1</param-name>
        <param-value>value1</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>charset</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

然后,我们就可以在filter中使用FilterConfig获取这些初始化参数:

//部分代码

public class ContentType implements Filter{
    FilterConfig config;
    @Override
    public void destroy() {
        config=null;}

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        //获取初始化参数
        Enumeration e = config.getInitParameterNames();
        while(e.hasMoreElement){
            paramName = e.nextElement();
            paramValue = e.getInitParameter(paramName);
        }
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;}
}
(四)过滤器案例

1、执行公用业务代码
2、无效数据过滤(引入ckeditor客户端组件)
3、登陆权限的判断

这里写链接内容

二、监听器

监听器就是一个实现特定接口的普通Java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象触发某些事件后,监听器某个方法将立即被执行。
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为 ServletContext, HttpSession 和 ServletRequest 这三个域对象。
监听器划分为三种类型:

  • 监听三个域对象创建和销毁的事件监听器
  • 监听域对象中属性的增加和删除的事件监听器
  • 监听绑定到 HttpSession 域中的某个对象的状态的事件监听器。

(一)监听器的分类

1、监听对象创建/销毁的监听器接口

Interface ServletRequestListener
//用于监听ServletRequest对象的创建和销毁。
//主要方法有:
void    requestDestroyed(ServletRequestEvent sre)
void    requestInitialized(ServletRequestEvent sre)

Interface HttpSessionListener
//用于监听HttpSession对象的创建和销毁
//主要方法有:
void    sessionCreated(HttpSessionEvent se)
void    sessionDestroyed(HttpSessionEvent se)

//用于监听 ServletContext 对象的创建和销毁事件。
//主要方法有:
void    contextDestroyed(ServletContextEvent sce)
void    contextInitialized(ServletContextEvent sce)

2、监听对象属性的变化

Servlet规范定义了监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信息事件的监听器。这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。

Interface ServletRequestAttributeListener
//主要方法有:
void    attributeAdded(ServletRequestAttributeEvent srae)
void    attributeRemoved(ServletRequestAttributeEvent srae)
void    attributeReplaced(ServletRequestAttributeEvent srae)

Interface HttpSessionAttributeListener
//主要方法有:
void    attributeAdded(HttpSessionBindingEvent event)
void    attributeRemoved(HttpSessionBindingEvent event)
void    attributeReplaced(HttpSessionBindingEvent event)

Interface ServletContextAttributeListener
//主要方法有:
void    attributeAdded(ServletContextAttributeEvent event)
void    attributeRemoved(ServletContextAttributeEvent event)
void    attributeReplaced(ServletContextAttributeEvent event)

3、监听绑定到 HttpSession 域中的某个对象的变化

Servlet 规范中定义了两个特殊的监听器接口来帮助 JavaBean 对象了解自己在 Session 域中的这些状态,实现这两个接口的类不需要 web.xml 文件中进行注册。

保存在 Session 域中的可以有多种状态:

1、绑定到 Session 域中;从 Session 域中解除绑定;
2、随 Session 对象持久化到一个存储设备中(钝化);随 Session 对象从一个存储设备中恢复(活化)

Interface HttpSessionBindingListene
//监听对象绑定/解绑到session上的事件,即是将对象保存到session当中就会调用该对象实现该监听器类方法
Interface HttpSessionActivationListener
//实现了该接口的 JavaBean 对象可以感知自己被活化和钝化的事件

(二)监听器的的实现步骤

1、实现相应监听器的类

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
 * Description:
 * @author lee
 */
public class SessionListener implements HttpSessionListener{

    /**
     * Description:
     */
    @Override
    public void sessionCreated(HttpSessionEvent event) {
    }

    /**
     * Description:
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
    }
}

2、web.xml文件中配置监听器

开发人员只需在web.xml文件中使用标签配置好监听器,web容器就会自动把监听器注册到事件源中。一个 web.xml 文件中可以配置多个事件监听器,web 服务器按照它们在 web.xml 文件中的注册顺序来加载和注册这些 Serlvet 事件监听器。(这里不包括不用注册的两个监听器。)

<!-- web.xml文件部分 -->
<listener>
    <!-- 这里就是把listener包下的Listener类注册成为监听器 -->
    <lisntener-class>listener.Listener</listener-class>
</listener>

在Servlet3.0下,也可以通过注解@WebListener就可以实现监听器的注册,不需要在web.xml中进行配置。

(三)监听器案例

1、统计在线人数


三、过滤器和监听器的实例

(一)实例描述

一个网页,存储有员工信息。可以进行管理员的登陆,管理员可以浏览、修改员工信息。管理员可以看得到其他管理员的是否在线。实现步骤:

1、建立数据库

管理员:编号、名称、密码
员工:编号、名称

2、编写实体类

用于封装管理员和员工的信息
Admin.java、Employee.java

3、数据访问层

实现对数据的处理
IAdminDao.java 接口、IEmployeeDao.java 接口、AdminDao.java、EmployeeDao.java

4、数据库连接

实现连接数据库,获取数据。
JdbcUtils

5、Servlet

LoginServlet.java 登陆处理
IndexServlet.java 首页列表查询Servlet
LogoutServlet.java 退出处理

6、Jsp页面

Login.jsp
登陆成功, 提交到登陆Servlet处理其业务,跳转到员工列表
登陆失败,跳转到登陆!
List.jsp 退出功能,跳转到登陆页面

7、过滤器

只有登陆后,才可以访问员工列表。如果没有登陆,直接访问首页列表,要跳转到登陆!
LoginFilter.java 登陆验证过滤器
ContentType.java 编码过滤

8、监听器

监听servletContext对象的创建,储存在线管理员。登陆功能:用户登陆时候,把数据保存到servletContext中。退出功能;监听session销毁,把当前登陆用户从onlineuserlist移除!
ContextListener.java 监听整个的项目的启动,启动时就创建在线管理员列表。
SessionListener.java 监听管理员的登陆

描述图:

程序结构图:


注:这里使用了MySQL数据库,引用C3P0连接池、dbutil、jstl标签,以上这些都需要导入jar包。这里在这个网站中找到对应的jar包

(二)数据库设计

1、管理员数据库

2、员工数据库

(三)实体类

1、封装管理员信息的实体类

package entity;

/**
 * Description:
 * 一个用来封装管理员信息的实体类
 * 
 * @author lee
 * */
public class Admin {
    private int id;
    private String adName;
    private String password;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    public String getAdName() {
        return adName;
    }
    public void setAdName(String adName) {
        this.adName = adName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

}

2、封装员工信息的实体类

package entity;

/**
 * Description:
 * 封装则员工信息的实体类
 * 
 * @author lee
 *
 */
public class Employee {
    private int id;
    private String empName;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }


}

(四)数据库连接

package utils;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;

import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
 * Description:
 * 这里使用C3P0的JDBC连接池,来实现数据源和JNDI(标准的Java命名系统接口)绑定
 * 实现连接数据库,获取数据。
 * 
 * @author lee
 */
public class JdbcUtils {

    /**
     * C3P0连接池的核心工具类
     */
    private static DataSource dataSource;
    //静态初始化连接池
    //C3P0连接池会自动加载src目录下的c3p0-config.xml配置文件,来连接mysql数据库
    static{
        dataSource = new ComboPooledDataSource();
    }

    /**
     * Description:
     * 初始化DbUtils核心工具类对象,并返回
     * 
     * @return 返回DbUtils核心工具类对象
     */
    @Test 
    public static QueryRunner getQueryRunner(){
        //返回创建的QueryRuuner对象,并传入连接池对象
        return new QueryRunner(dataSource);
    }

}

c3p0-config.xml配置文件的编写

<c3p0-config>
  <default-config>
    <!-- mysql数据库的url地址 -->
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/data</property>
    <!-- mysql数据库的驱动 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <!-- 数据库的用户名称 -->
    <property name="user">root</property>
    <!-- 数据库的用户的密码 -->
    <property name="password">123456</property>
    <!-- 连接池保持的最小连接数 -->
    <property name="initialPoolSize">3</property>
    <!-- 链接池保持的最大连接数 -->
    <property name="maxPoolSize">6</property>
    <!-- 最大空闲时间,600秒内未使用则连接被丢弃。若为0则永不丢弃。默认为0  -->
    <property name="maxIdleTime">600</property>
  </default-config>
</c3p0-config>
(五)数据访问层

1、管理员数据访问层接口

package dao;
import entity.Admin;
/*
 * Description:
 * 管理员数据访问层接口
 * 
 * @author lee
 */
public interface IAdminDao {
    /**
     * Description:
     * 根据管理员名称来获取管理员信息
     * 
     * @param adName 管理员的名称
     * @return 返回封装着管理员信息的Admin类
     */
    Admin findByName(String adName);
}

2、员工数据访问层的接口

package dao;
import java.util.List;
import entity.Employee;

/*
 * Description:
 * 员工数据访问层的接口
 * 
 * @author lee
 */
public interface IEmployeeDao {
    /**
     * Description:
     * 返回一个包含所有着员工信息集合
     * 
     * @return 返回一个包含所有着员工信息集合
     */
    List<Employee> findAll();
}

3、管理员数据访问层接口的实现类

package dao.impl;

import java.sql.SQLException;

import org.apache.commons.dbutils.handlers.BeanHandler;

import dao.IAdminDao;
import entity.Admin;
import utils.JdbcUtils;

/**
 * Description:
 * 管理员数据访问层接口的实现类
 * 
 * @author lee
 *
 */
public class AdminDao implements IAdminDao{

    /**
     * Description:
     * 调用JdbcUtils的方法执行sql的查询语句,根据指定的管理员名称来获取管理员信息。
     * 如果找不到对应名称的管理员,则返回null
     * 
     * public T BeanHandler.handle(ResultSet rs) throws SQLException
     * An initialized JavaBean or null if there were no rows in the ResultSet
     * 
     * @param adName 管理员的名称
     * @return 返回封装着管理员信息的Admin类
     */
    @Override
    public Admin findByName(String adName) {
        //sql查询语句
        String sql = "select * from admin where adName=?";

        try {
            //执行sql查询语句,使用dbUtil工具类,
            //将查询语句返回的数据表(ResultSet)第一行的封装成一个JavaBean(即是封装管理员信息实体类Admin)
            //that converts the first ResultSet row into a JavaBean. 
            return JdbcUtils.getQueryRunner()
                    .query(sql,new BeanHandler<Admin>(Admin.class),adName);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args){
        Admin admin = new AdminDao().findByName("lee");
        if(admin!=null)
            System.out.println(admin.getAdName()+","+admin.getPassword());

    }
}

4、员工数据访问层接口的实现类

package dao.impl;

import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import dao.IEmployeeDao;
import entity.Employee;
import utils.JdbcUtils;

/**
 * Description:
 * 员工数据访问层接口的实现类
 * 
 * @author lee
 *
 */
public class EmployeeDao implements IEmployeeDao{

    /**
     * Description:
     * 同过调用JdbcUtils的方法执行sql查询语句,来获取所有员工的数据。
     * 
     * @return List<Employee>一个包含所有员工信息的集合,假如没有则返回null
     */
    @Override
    public List<Employee> findAll() {
        //sql查询语句
        String sql = "select * from employee";
        try {
            //执行sql查询语句,使用dbUtil工具类,
            //将查询语句返回的数据库结果集的数据表(ResultSet)封装成一个JavaBean的集合
            //that converts the first ResultSet 
            return JdbcUtils.getQueryRunner()
                    .query(sql,new BeanListHandler<Employee>(Employee.class));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

}
(六)Servlet

1、LoginServlet.java 登陆处理

package servlet;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


import dao.impl.AdminDao;
import entity.Admin;

/**
 * Description:
 * 管理员的登陆验证
 * 
 * @author lee
 */
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    /**
     * Description:
     * 转发的uri
     * 
     */
    String uri;

    /**
     * Description:
     * 管理员的登陆验证。从表单中获取管理员的名称和密码,并与数据库中的管理员信息相比较。
     * 如果名称和密码相匹配,则登陆成功,转发到员工列表页面。
     * 否则转发进入登陆页面。
     * 
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //获取表单的提交的管理员名称和密码
        String userName = request.getParameter("userName");
        String password = request.getParameter("password");

        //从数据库中差查找指定的名称的管理员的信息,由Admin封装着
        Admin admin = new AdminDao().findByName(userName);

        //当密码相匹配,则转发员工列表页面,否则转发进入登陆页面
        if(admin!=null&&password.equals(admin.getPassword())){
            //获取session
            HttpSession session = request.getSession();
            //设置session的最大保留时间
            session.setMaxInactiveInterval(60);

            //假如session没有管理员的信息,则将该管理员的信息保存在session域当中
            if(session.getAttribute("admin")==null){
                //将封装管理员信息的admin保存在session域中
                session.setAttribute("admin", admin);

                //获取在线管理员列表
                @SuppressWarnings("unchecked")
                List<Admin> admins = (List<Admin>)request.getServletContext().getAttribute("admins");
                if(admins!=null){
                    //将管理员信息添加到在线管理员列表
                    admins.add(admin);
                }
            }

            uri = "/IndexServlet";
        }else{
            uri = "login.jsp";
        }

        //转发页面
        request.getRequestDispatcher(uri).forward(request,response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

2、IndexServlet.java 首页列表查询Servlet

package servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import dao.impl.EmployeeDao;
import entity.Admin;
import entity.Employee;

/**
 * Description:
 * 获取所有员工信息
 * 
 * @author lee
 */
@WebServlet("/IndexServlet")
public class IndexServlet extends HttpServlet {
    /**
     * Description:
     * 转发的uri
     * 
     */
    String uri;

    /**
     * Description:
     * 获取所有员工信息,并将其保存在session域中
     * 
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取所有装载员工信息实体的集合
        List<Employee> list = new EmployeeDao().findAll();

        //假如能获取所有员工信息则将其保存在session域,否则转发进入错误页面
        if(list!=null){
            HttpSession session = request.getSession(false);
            session.setAttribute("list",list);

            uri="list.jsp";
        }else{
            uri="error.jsp";
        }

//      @SuppressWarnings("unchecked")
//      List<Admin> admins = (List<Admin>)request.getServletContext().getAttribute("admins");
//      if(admins!=null){
//          Iterator<Admin> i = admins.iterator();
//          while(i.hasNext()){
//              Admin admin = (Admin)i.next();
//              System.out.println(admin.getAdName());
//          }
//      }else{
//          System.out.println("该在线列表不存在");
//      }


        //转发
        request.getRequestDispatcher(uri).forward(request,response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

3、LogoutServlet.java 退出处理

package servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Description:
 * 销毁管理员的session
 * 
 * Servlet implementation class LogoutServlet
 */
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {

    /**
     * Description:
     * 当管理员点击退出时,销毁管理员的session
     * 
     * Invalidates this session then unbinds any objects bound to it.
     * 
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取session,销毁session
        HttpSession session = request.getSession();
        if(session!=null){
            session.invalidate();
        }

        //重定向到登陆页面
        response.sendRedirect("login.jsp");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
(八)Jsp页面

1、Login.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>登录页面</title>
</head>
<body>

    <!-- 将表单提交到LoginServle处理 -->
    <form align="center" style="position:relative;top:100px" 
                    name="form" 
                    action="${pageContext.request.contextPath}/LoginServlet" 
                    method="post">

        <h2 style="margin:25px">欢迎登陆</h2>
        <!-- 假如session有保存管理员的信息,则名称和密码的值为管理员对应的名称和密码  -->
        用户名:<input type="text" name="userName" value="${admin.adName}"><br>
        密码:&nbsp;&nbsp;&nbsp;&nbsp;<input type="password" name="password"  value="${admin.password}"><br>
        <input align= "center" type="submit" name="登陆">
    </form>
</body>
</html>

2、List.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!-- 导入Admin实体类 -->
<%@ page language="java" import="entity.Admin" %>
<!-- 导入jstl核心标签 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>员工列表</title>
</head>
<body>
    <h3 align="center">欢迎管理员${admin.adName}登陆!</h3><br><br>

    <!-- 循环员工列表 -->
    <h3 align="center">员工列表</h3>
    <table align="center" border="1">
            <tr>
                <td>员工编号</td>
                <td>员工名称</td>
            </tr>
        <c:forEach items="${list}" var="var">
            <tr>
                <td>${var.id}</td>
                <td>${var.empName}</td>
            </tr>
        </c:forEach>
    </table>

    <br><br>
    <c:if test="${not empty admins}">
        <p align="right" style="position:relative;right:10px;font-size:20px">
            当前在线管理员:<br>
            <c:forEach items="${admins}" var="var">
                ${var.adName}&nbsp;&nbsp;
            </c:forEach>
        </p>
    </c:if>
    <div align="right" style="position:relative;right:30px;font-size:20px"><a href="${pageContext.request.contextPath }/LogoutServlet" >退出</a></div>
</body>
</html>
(九)过滤器

1、ContentType.java 编码过滤

package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;


/**
 * Description:
 * 设置编码格式
 * 
 * @author lee
 */
public class ContentType implements Filter{
    FilterConfig config;
    @Override
    public void destroy() {
        config=null;

    }

    /**
     * Description:
     * 设置编码格式
     * 
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        //设置编码格式
        resp.setContentType("text/html;charset=utf-8");
        chain.doFilter(req, resp);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }

}

2、LoginFilter.java 登陆验证过滤器

package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Description:
 * 拦截没有登陆的管理员进入查看员工列表页面
 * 
 * @author lee
 */
public class LoginFilter implements Filter {
    FilterConfig  config;

    @Override
    public void destroy() { 
        config = null;
    }

    /*
     * Description:
     * 当用户直接访问员工列表页面时,需要通过session保存的信息来判断是否已经登陆,
     * 假如已经登陆后,则直接进入员工列表,假如没有登陆则转入登陆页面
     * 
     * (non-Javadoc)
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest res = (HttpServletRequest)request;
        HttpServletResponse resp = (HttpServletResponse)response;

        //获取请求的uri
        String uri = res.getRequestURI();

        //请求直接访问员工列表页面时
        if("/web/list.jsp".equals(uri)
                ||"/web/IndexServlet".equals(uri)){
            //获取session
            HttpSession session = res.getSession(false);

            //判断session是否保存有登陆信息,已经登陆(即是session保存有其管理员的信息)
            //则可以直接访问员工列表
            //否则,则重定向登陆页面
            if(session!=null
                    &&session.getAttribute("admin")!=null)
                chain.doFilter(res, resp);
            else
                resp.sendRedirect("login.jsp");
        }else{
            //访问其他页面,则直接通过
            chain.doFilter(res, resp);
        }

    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }

}
(十)监听器

1、ContextListener

package listener;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import entity.Admin;

/**
 * Decsription:
 * 监听整个当前项目,维护一个当前用户登陆列表。
 * 
 * @author lee
 *
 */
public class ContextListener implements ServletContextListener{

    public static List<Admin> admins = new ArrayList<Admin>();


    /**
     * Decsription:
     * 当真个项目销毁是,销毁该用户登陆列表
     * 
     */
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        Object admins = event.getServletContext().getAttribute("admins");
        if(admins!=null)
            event.getServletContext().removeAttribute("admins");

    }

    /**
     * Description:
     * 当整个项目被创建时,初试化一个当前用户登陆列表
     * 
     */
    @Override
    public void contextInitialized(ServletContextEvent event) {
        System.out.println("初始化在线用户列表..");
        event.getServletContext().setAttribute("admins",admins);
    }

}

2、SessionListener.java

package listener;

import java.util.List;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import entity.Admin;

/**
 * Description:
 * 记录session保存的用户
 * 
 * @author lee
 *
 */
public class SessionListener implements HttpSessionListener{

    /**
     * Description:
     * 当记录用户的session别创建时,则将其保存在在线用户列表
     */
    @Override
    public void sessionCreated(HttpSessionEvent event) {
//      HttpSession session = event.getSession();
//      System.out.println("初始化session");
//      @SuppressWarnings("unchecked")
//      List<Admin> admins = (List<Admin>) session.getServletContext().getAttribute("admins");
//      if(admins!=null){
//          Admin admin  = (Admin)session.getAttribute("admin");
//          if(admin!=null){
//              System.out.println(admin.getAdName());
//              admins.add(admin);
//          }
//      }
    }

    /**
     * Description:
     * 当记录用户的session被销毁是,则将其从在线用户列表中移除
     * 
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        //获取session
        HttpSession session = event.getSession();

        //获取在线用户列表
        @SuppressWarnings("unchecked")
        List<Admin> admins = (List<Admin>) event.getSession().getServletContext().getAttribute("admins");
        if(admins!=null){
            //获取session的用户信息
            Admin admin  = (Admin)session.getAttribute("admin");
            //将用户从在线列表中移除
            admins.remove(admin);
        }

    }


}
(十一)web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
            id="WebApp_ID" 
            version="3.1">
  <display-name>web</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>loginServlet</servlet-name>
    <servlet-class>servlet.LoginServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>loginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

  <filter>
    <filter-name>charset</filter-name>
    <filter-class>filter.ContentType</filter-class>
  </filter>
  <filter>
    <filter-name>loginFilter</filter-name>
    <filter-class>filter.LoginFilter</filter-class>

  </filter>

  <filter-mapping>
    <filter-name>charset</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>loginFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>

  <listener>
    <listener-class>listener.ContextListener</listener-class>
  </listener>
  <listener>
    <listener-class>listener.SessionListener</listener-class>
  </listener>

  <error-page>
    <error-code>404</error-code>
    <location>/notFound.jsp</location>
  </error-page>
  <error-page>
    <error-code>500</error-code>
    <location>/error.jsp</location>
  </error-page>
</web-app>
(十二)效果

原链接:http://blog.csdn.net/qq1131410679/article/details/75151080

评论
条评论