javax.servlet.Filter
接口的类 URL路径模式
和```Servlet名称 <filter> <filter-name>characterFilter</filter-name> <filter-class>com.yueqian.store.filter.characterFilter</filter-class> </filter> <!-- 过滤器执行的顺序和Filter-mapping顺序有关,可以设置多个dispatcher,表示哪些请求都需要过滤,默认为REQUEST为对客户端得请求进行过滤 --> <filter-mapping> <filter-name>characterFilter</filter-name> <url-pattern>/*</url-pattern> <servlet-name>userServlet</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping> 复制代码
package com.yueqian.store.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.annotation.WebFilter; import javax.servlet.annotation.WebServlet; @WebFilter("/*") public class characterFilter implements Filter{ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("Filter实例被过滤执行了。。。"); //设置请求响应编码 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); chain.doFilter(request, response);//交给下面所有的过滤器链 } @Override public void destroy() { System.out.println("Filter实例被销毁了。。。"); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Filter实例被初始化了。。。"); } } 复制代码
package com.yueqian.store.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.annotation.WebFilter; @WebFilter("/*") public class LogFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String remote = request.getRemoteAddr()+":"+request.getRemoteHost()+":"+request.getRemotePort(); long start = System.currentTimeMillis(); chain.doFilter(request, response); long end = System.currentTimeMillis(); System.out.println(remote+"执行了"+(end-start)+"毫秒!"); } @Override public void destroy() { } @Override public void init(FilterConfig filterConfig) throws ServletException { } } 复制代码
package com.yueqian.store.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.yueqian.store.common.Constans; @WebFilter("/*") //使用注解的过滤器执行顺序是按照类名字典排序 /** * 对登录请求进行过滤 * @author LinChi * */ public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest rep = (HttpServletRequest)request; HttpServletResponse resp = (HttpServletResponse)response; //放过所有不需要检查的资源文件(图片、样式、脚本、验证码、登陆注册界面) String uri = rep.getRequestURI(); if(uri.contains("login.jsp") || uri.contains("register.jsp") || uri.contains("nologin.jsp") || uri.endsWith(".jpg") || uri.endsWith(".css") || uri.endsWith(".jpeg") || uri.endsWith(".js") || uri.contains("/user/login") || uri.contains("/user/logout") || uri.contains("/user/register") || uri.contains("/verify")) { chain.doFilter(request, response);//放过这些不需要检查的资源文件 return; } Object login = rep.getSession().getAttribute(Constans.SESSION_LOGINED_INFO); if(login == null) { resp.sendRedirect(rep.getContextPath()+"/login.jsp"); }else { chain.doFilter(request, response); } } } 复制代码
package com.yueqian.store.listener; import java.util.LinkedList; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import com.yueqian.store.common.Constans; import com.yueqian.store.common.DBUtils; /** * 应用程序上下文监听器(监听Servletontext对象的创建与销毁) * 监听整个服务器开启时的动作和关闭时的动作 * @author LinChi * */ @WebListener public class ApplicationListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent event) { System.out.println("数据库连接池关闭了。。。"); //程序结束时关闭数据库连接池 DBUtils.closeDataSourse(); } @Override public void contextInitialized(ServletContextEvent event) { System.out.println("数据库连接池开启了。。。"); //程序开启时初始化数据库连接池 DBUtils.init(); //给servletContext对象添加一个列表,用来存放登录系统用户的数量 event.getServletContext().setAttribute(Constans.APPLICATION_LIST_ID, new LinkedList<>()); } } 复制代码
package com.yueqian.store.common; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.Map; import org.apache.tomcat.dbcp.dbcp2.BasicDataSource; public class DBUtils { private static final String URL = "jdbc:mysql://127.0.0.1:3306/store?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false"; private static final String USERNAME = "root"; private static final String PASSWORD = "root"; private static BasicDataSource ds = null; public static void init() { // 加载驱动 try { // 方式一 DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver()); // 方式二 根据传入字符串形式的类名加载该类 (加载类时调用静态代码块加载驱动) // Class.forName("com.mysql.cj.jdbc.Driver()"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } // 创建数据库连接池 ds = new BasicDataSource(); // 设置连接信息 ds.setDriverClassName("com.mysql.cj.jdbc.Driver"); ds.setUrl(URL); ds.setUsername(USERNAME); ds.setPassword(PASSWORD); // 设置连接池信息 // 最大空闲连接数 ds.setMaxIdle(30); // 最小空闲连接数 ds.setMinIdle(2); // 设置初始连接数 ds.setInitialSize(2); // 创建连接时最大等待时间 ds.setMaxWaitMillis(4000);// 毫秒 // 从数据源中拿到的连接,关闭其自动提交的事务 ds.setDefaultAutoCommit(false); } // 定义连接保存在ThreadLocal类中,将当前线程对象作为key,保存连接conn对象,避免多线程访问业务层和dao层导致使用的conn连接不一致问题 // service里绑定每个线程对象的连接,调用的dao层获取该处理线程对象的连接 private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(); /** * 连接数据库 * * @return */ public static Connection getConnection() { //先从threadLocal中获得连接,threadLocal类似map存放,ThreadLocal中是以键为当前线程对象,值为conn连接存放的。 Connection conn = threadLocal.get(); //如果连接为null,从连接池中获取连接 if (conn == null) { try { conn = ds.getConnection(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } //将得到的连接设置到threadLocal中 threadLocal.set(conn); } return conn; } /** * 关闭连接 * * @param rs * @param stmt * @param conn */ public static void close(ResultSet rs, Statement stmt) { if (rs != null) { try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } // 提交事务 public static void commit() { Connection conn = threadLocal.get(); if(conn != null){ try { conn.commit(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { //关闭连接 try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } //清理当前线程所绑定的连接 threadLocal.remove(); } } } // 回滚事务 public static void rollback() { Connection conn = threadLocal.get(); if(conn != null){ try { conn.rollback(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { //关闭连接 try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } //清理当前线程所绑定的连接 threadLocal.remove(); } } } /** * 关闭数据库连接池 */ public static void closeDataSourse() { if(ds != null) { try { ds.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } 复制代码
package com.yueqian.store.listener; import javax.servlet.ServletContext; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import com.yueqian.store.common.Constans; /** * 监听session创建和销毁 * 根据session创建的数目来统计访问系统人数的数目(不同浏览器、同一个用户登录也是在线两人,创建两个session,所以不太准确,游客) * * @author LinChi * */ //@WebListener public class OnLineListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent event) { // 获取上下文对象 ServletContext context = event.getSession().getServletContext(); // 获取上下文对象中存在的session数目 Integer count = (Integer) context.getAttribute(Constans.APPLICATION_SESSION_ID); if (count == null) { count = 1; } else { count++; } context.setAttribute(Constans.APPLICATION_SESSION_ID, count); } /** * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { // 获取上下文对象 ServletContext context = event.getSession().getServletContext(); // 获取上下文对象中存在的session数目 Integer count = (Integer) context.getAttribute(Constans.APPLICATION_SESSION_ID); if(count != null) { count--; context.setAttribute(Constans.APPLICATION_SESSION_ID, count); } } } 复制代码
当前访问系统人数:<% Integer count = (Integer)application.getAttribute(Constans.APPLICATION_SESSION_ID); if(count != null){ out.print(count); } %>人。 复制代码
package com.yueqian.store.domain; import java.util.List; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import com.yueqian.store.common.Constans; /** * 实现精确实现在线人数的统计 * * @author LinChi * */ public class UserInfo implements HttpSessionBindingListener { private Integer userId; private String account; private String username; private String password; public UserInfo() { super(); // TODO Auto-generated constructor stub } public UserInfo(Integer userId, String account, String username, String password) { super(); this.userId = userId; this.account = account; this.username = username; this.password = password; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "UserInfo [userId=" + userId + ", account=" + account + ", username=" + username + ", password=" + password + "]"; } // 当UserInfo对象被设置到session中,此方法被执行 @Override public void valueBound(HttpSessionBindingEvent event) { // 将当前UserInfo对象的账号保存到列表中,通过列表中账号的数量来统计登录系统的人数 ServletContext context = event.getSession().getServletContext(); // 从应用程序监听器中获得访问用户列表 List<String> list = (List<String>) context.getAttribute(Constans.APPLICATION_LIST_ID); // 当列表中不包含此用户,添加(防止同时添加同一个用户) if (!list.contains(this.account)) { list.add(this.account); } } // 当UserInfo对象从session对象中删除时,此方法被执行 @Override public void valueUnbound(HttpSessionBindingEvent event) { // 将当前UserInfo对象的账号保存到列表中,通过列表中账号的数量来统计登录系统的人数 ServletContext context = event.getSession().getServletContext(); // 从应用程序监听器中获得访问用户列表 List<String> list = (List<String>) context.getAttribute(Constans.APPLICATION_LIST_ID); //删除对象 list.remove(this.account); } } 复制代码
在线人数:<% List<String> list = (List<String>)application.getAttribute(Constans.APPLICATION_LIST_ID); if(list != null){ out.print(list.size()); }else{ out.print("0"); } %>人<br/> <% for(String account:list){ %> <%out.print(account+" ");} %> 复制代码
好了,今天的内容就到此了,有了今天的整理,我们以后在项目中要使用过滤器和监听器,就可以cv操作了,期待下期的精彩展示吧!