Java学习笔记-Day58 监听器、分页、Layui前端框架


一、监听器

1、简介


事件发生的时间往往是不确定的,当事件发生的时候需要进行一些处理时,就可以使用监听器。

在这里插入图片描述

2、监听器相关的API


监听器相关的API包括 事件类 以及 监听器接口。事件类定义了事件类型,监听器接口定义了监听事件的方法。

2.1、事件类


Servlet API中定义了6种事件类型:
(1)上下文相关的事件

  • ServletContextEvent:该类表示上下文事件,当应用上下文对象发生改变,如创建或销毁上下文对象时,将触发上下文事件。
  • ServletContextAttributeEvent:该类表示上下文属性事件,当应用上下文的属性改变,如增加、删除、覆盖上下文中的属性时,将触发上下文属性事件。

(2)请求相关的事件

  • ServletRequestEvent:该类表示请求事件,当请求对象发生改变,如创建或销毁请求对象时,触发请求事件。
  • ServletRequestAttributeEvent:该类表示请求属性事件,当请求中的属性改变,如增加、删除、覆盖请求中的属性时,触发请求属性事件。

(3)会话相关的事件

  • HttpSessionEvent:该类表示会话事件,当会话对象发生改变,如创建或销毁会话对象,活化或钝化会话对象时,将触发会话事件。
  • HttpSessionBindingEvent:该类表示会话绑定事件,当会话中的属性发生变化时,如增加、删除、覆盖会话中的属性时,将触发会话绑定事件。

2.2、监听器接口


Servlet API中定义了8种监听器接口,用来监听不同的事件类型。
(1)上下文相关的监听器

扫描二维码关注公众号,回复: 12647911 查看本文章
  • ServletContextListener:上下文监听器,监听ServletContextEvent事件。
  • ServletContextAttributeListener:上下文属性监听器,用来监听ServletContextAttribute事件。

(2)请求相关的监听器

  • ServletRequestListener:请求监听器,监听ServletRequestEvent事件。
  • ServletRequestAttributeListener:请求属性监听器,用来监听ServletRequestAttributeEvent事件。

(3)会话相关的监听器

  • HttpSessionListener:会话监听器,监听HttpSessionEvent。当会话对象被创建后或销毁前需要一些自定义处理时,可以用此监听器监听,

  • HttpSessionActivationListener:会话活化监听器,监听HttpSessionEvent事件。会话对象存在于服务器端,只要没有失效,服务器就得分配空间给其使用;为了能够提高使用效率,服务器有内在的活化钝化机制,可以将暂时不使用的会话对象钝化到外存,需要使用时再活化到内存。当活化后或钝化前需要一些自定义处理时,可以使用该监听器。

  • HttpSessionAttributeListener:会话属性监听器,监听HttpSessionAttributeEvent事件。当会话中的属性被添加、删除、替换时,要进行一些自定义处理时,可以使用该监听器,使用时可以用事件对象获取属性的名字等信息。

  • HttpSessionBindingListener:会话绑定监听器,监听HttpSessionAttributeEvent事件。当类实现了HttpSessionBindingListener接口后,该类对象绑定或解除绑定到会话时,就会被该监听器监听。绑定指的是调用setAttribute方法,解除绑定指的是调用removeAttribute方法,或者会话超时、会话失效等。

3、监听器的开发及配置


(1)自定义一个类,并实现相应的监听器接口。

(2)重写监听器接口中的方法。

(3)让监听器生效,需要在web.xml或者注解中进行配置。

  • 在web.xml中的配置:
	<listener>
		<listener-class>com.etc.bs.TestListener</listener-class>
	</listener>

  • 在自定义类的前一行写注解:
	@WebListener
	public class OnlineCountListener implements HttpSessionListener {
    
    }

4、Eclispe创建监听器


(1)鼠标右键 -> New -> Listener -> 输入包名和类名 -> Next -> 选择进行监听的事件 ( 例如:HTTP session events 的 Lifecycle ) -> Finsh。

在这里插入图片描述

5、案例 (统计在线人数)


servlet中对session的监听有很多接口,功能很灵活,最常用的是监听Session和Attribute。servlet中的session监听和Attribute监听含义有差别,session监听指的不是我们一般所理解的放置一个session或者销毁一个session,这是Attribute监听的功能,因为servlet中放置session的语法是session.setAttribute(“session名”,要放入的对象)。而session监听,监听的是HTTP连接,只要有用户与server连接,就算连接的是一个空白的jsp页面,也会触发session事件,所以此处的session实际上指的是connection,最合适用来统计当前在线人数。

使用监听器 HttpSessionListener,将计数的变量储存在application中,可以通过如下代码获取appliacation。

	ServletContext application = se.getSession().getServletContext();

统计在线人数的监听器:

package com.etc.bs.listener;

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * 统计在线人数
 *
 */
@WebListener
public class OnlineCountListener implements HttpSessionListener {
    
    
	//统计Session数量
	private static int count = 0;
    /**
     * 	无参构造方法
     */
    public OnlineCountListener() {
    
    
    	System.out.println("OnlineCountListener构造方法");
    }

	/**
     * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
     */
    public void sessionCreated(HttpSessionEvent se)  {
    
     
    	System.out.println("session的创建");
    	++count;
        ServletContext application = se.getSession().getServletContext();
        application.setAttribute("count", count);
    }

	/**
     * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
     */
    public void sessionDestroyed(HttpSessionEvent se)  {
    
     
    	System.out.println("session的销毁");
    	--count;
        ServletContext application = se.getSession().getServletContext();
        application.setAttribute("count", count);
    }
	
}

二、分页

1、分页的方式


(1)逻辑分页:一次性查询所有数据,在前端代码实现分页功能。

	SELECT * FROM users;

(2)物理分页:每次只查询当前页的数据,每次都会向数据库发送一次查询请求。

	SELECT * FROM users LIMIT 1,5;"

2、分页的要素


实现分页需要的五个要素:

(1)当前页数(当前第几页)。
(2)每页显示的记录数(每页显示几条数据)。
(3)总记录数(总共多少条记录)。
(4)总页数(总共有几页)。
(5)当前页的数据。

可以将这些要素封装成一个PageData类。

package com.etc.bs.entity;

import java.util.List;

public class PageData<T> {
    
    
	// 当前页数
	private int pageNo;
	// 每页的记录数
	private int pageSize;
	// 总记录数
	private int totalCount;
	// 总页数
	private int totalPage;
	// 当前页的数据
	private List<T> list;
	
	public int getPageNo() {
    
    
		return pageNo;
	}
	public void setPageNo(int pageNo) {
    
    
		this.pageNo = pageNo;
	}
	public int getPageSize() {
    
    
		return pageSize;
	}
	public void setPageSize(int pageSize) {
    
    
		this.pageSize = pageSize;
	}
	public int getTotalCount() {
    
    
		return totalCount;
	}
	public void setTotalCount(int totalCount) {
    
    
		this.totalCount = totalCount;
	}

	public List<T> getList() {
    
    
		return list;
	}
	public void setList(List<T> list) {
    
    
		this.list = list;
	}
	/**
	 * 总页数totalPage的get方法
	 * @return 返回一个总页数
	 */
	public int getTotalPage() {
    
    
		totalPage = totalCount/pageSize;
		if((totalCount%pageSize) != 0) {
    
    
			totalPage = totalPage+1;
		}
		return totalPage;
	}
	
	@Override
	public String toString() {
    
    
		return "PageData [pageNo=" + pageNo + ", pageSize=" + pageSize + ", totalCount=" + totalCount + ", totalPage="
				+ totalPage + "]";
	}

}

3、增加了分页查询的通用类

package com.etc.bs.utils;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;

import com.etc.bs.entity.PageData;

/**
 * 数据库访问的通用类,其中,实现了增加删除修改通用操作;实现了查询多行记录的通用操作;
 * 
 *
 */
public class DBUtil {
    
    
	//数据库连接的url
	private static final String url = "jdbc:mysql://localhost:3306/blogdb?useSSL=FALSE&serverTimezone=Asia/Shanghai";
	//数据库连接的user
	private static final String user = "root";
	//数据库连接的password
	private static final String password = "root";
	
	private DBUtil() {
    
    
		
	}

	/**
	 * 建立数据库连接Connection
	 * 
	 * @return conn 数据库连接
	 */
	public static Connection getConn() {
    
    
		Connection conn = null;
		try {
    
    
			// 加载驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			// 创建数据库连接
			conn = DriverManager.getConnection(url, user, password);
		} catch (Exception e) {
    
    
			e.printStackTrace();
		}
		return conn;
	}

	/**
	 * 封装的增加、删除和修改的通用代码(针对任何表)
	 * 
	 * @param sql    sql语句
	 * @param params sql语句的参数
	 * @return true 操作成功;false 操作失败
	 */
	public static boolean exUpdate(String sql, Object... params) {
    
    
		Connection conn = null;
		PreparedStatement pstmt = null;
		int n = 0;

		try {
    
    
			conn = getConn();
			pstmt = conn.prepareStatement(sql);
			// 给空格占位符赋值
			setParameters(pstmt, params);
			// 执行具体操作,获取结果集
			n = pstmt.executeUpdate();
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		} finally {
    
    
			// 释放资源
			closeAll(null, pstmt, conn);
		}
		return n > 0;
	}

	/**
	 * 设置PreparedStatement的SQl语句的参数
	 * 
	 * @param pstmt  PreparedStatement对象
	 * @param params sql语句的参数
	 * @throws SQLException SQLException异常
	 */
	private static void setParameters(PreparedStatement pstmt, Object... params) throws SQLException {
    
    
		if (params != null) {
    
    
			for (int i = 0; i < params.length; i++) {
    
    
				pstmt.setObject(i + 1, params[i]);

			}
		}
	}

	/**
	 * 封装的查询的通用代码(返回的结果是一个集合)
	 * 
	 * @param sql    Sql语句
	 * @param cla    Class对象
	 * @param params sql语句的参数
	 * @return List 集合
	 */
	public static List exQuery(String sql, Class cla, Object... params) {
    
    
		List list = new ArrayList();
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
    
    
			// 获取PreparedStatement对象
			conn = getConn();
			pstmt = conn.prepareStatement(sql);
			// 给空格占位符赋值
			setParameters(pstmt, params);
			// 发送Sql语句,获得结果集
			rs = pstmt.executeQuery();
			
			// 遍历结果集,最初光标指向第一行之前,通过next()方法向下移动一行
			while (rs.next()) {
    
    
				// 将当前这一行的所有列的值赋值给对象的属性
				Object obj = convert(rs, cla);
				// 将获取的对象obj添加到List集合中
				list.add(obj);
			}
		
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		} finally {
    
    
			closeAll(rs, pstmt, conn);
		}

		return list;
	}
	
	/**
	 * 查询总记录数的方法
	 * @param sql sql语句
	 * @param params 参数
	 * @return int 总记录数 
	 */
	public static int exCountQuery(String sql, Object... params) {
    
    
		//总记录数
		int totalCount = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
    
    
			// 获取PreparedStatement对象
			conn = getConn();
			pstmt = conn.prepareStatement(sql);
			// 给空格占位符赋值
			setParameters(pstmt, params);
			// 发送Sql语句,获得结果集
			rs = pstmt.executeQuery();
			if (rs.next()) {
    
    
				// 检索当前行中指定列的值
				totalCount = rs.getInt("c");
			}
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		} finally {
    
    
			closeAll(rs, pstmt, conn);
		}
		return totalCount;
	}
	
	/**
	 * 分页查询的方法
	 * @param sql sql语句
	 * @param cla 类
	 * @param pageNo 当前页数
	 * @param pageSize 当前页的记录数
	 * @param params 参数
	 * @return PageData
	 */
	public static PageData exQueryByPage(String sql, Class cla, int pageNo,int pageSize,Object... params) {
    
    
		List list = new ArrayList();
		// 拼接查询总记录数的sql语句
		String totalCountSql = "select count(*) as c from ("+sql+") as t;"; 
		// 调用exCountQuery方法,返回一个总记录数
		int totalCount = exCountQuery(totalCountSql, params);
		// 计算开始的索引( 索引=(当前页数-1)*每页记录数)
		int start = (pageNo-1) * pageSize;
		// 拼接查询分页数据的sql语句
		sql = sql+" limit "+start+","+pageSize+";";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
    
    
			// 获取PreparedStatement对象
			conn = getConn();
			pstmt = conn.prepareStatement(sql);
			// 给空格占位符赋值
			setParameters(pstmt, params);
			// 发送Sql语句,获得结果集
			rs = pstmt.executeQuery();
			
			// 遍历结果集,最初光标指向第一行之前,通过next()方法向下移动一行
			while (rs.next()) {
    
    
				// 将当前这一行的所有列的值赋值给对象的属性
				Object obj = convert(rs, cla);
				// 将获取的对象obj添加到List集合中
				list.add(obj);
			}
		
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		} finally {
    
    
			closeAll(rs, pstmt, conn);
		}
		PageData pd = new PageData();
		//设置当前页数
		pd.setPageNo(pageNo);
		//设置当前页的记录数
		pd.setPageSize(pageSize);
		//设置总页数
		pd.setTotalCount(totalCount);
		//设置当前页的数据
		pd.setList(list);
		return pd;
	}

	/**
	 * 转换方法 将rs读取结果转换对象
	 * 
	 * @param rs  rs对象
	 * @param cla Class对象
	 * @return Object对象
	 */
	private static Object convert(ResultSet rs, Class cla) {
    
    
		Object obj = null;
		try {
    
    
			obj = cla.newInstance();
			ResultSetMetaData rsm = rs.getMetaData();
			// getColumnCount:返回此 ResultSet对象中的总列数(从1开始)
			for (int i = 1; i <= rsm.getColumnCount(); i++) {
    
    
				// getColumnLabel:获取指定列名(如果列有别名,则获取列的别名)
				String name = rsm.getColumnLabel(i);
				Object objvalue = rs.getObject(name);
				// setProperty:直接设置对象属性的值,会调用对象的setter方法
				BeanUtils.setProperty(obj, name, objvalue);
			}
		} catch (SQLException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
    
    
			e.printStackTrace();
		}
		return obj;
	}

	/**
	 * 释放资源
	 * 
	 * @param rs    ResultSet对象
	 * @param pstmt PreparedStatement对象
	 * @param conn  Connection对象
	 */
	public static void closeAll(ResultSet rs, PreparedStatement pstmt, Connection conn) {
    
    
		try {
    
    
			if (rs != null) {
    
    
				rs.close();
			}
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		}
		try {
    
    
			if (pstmt != null) {
    
    
				pstmt.close();
			}
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		}
		try {
    
    
			if (conn != null) {
    
    
				conn.close();
			}
		} catch (SQLException e) {
    
    
			e.printStackTrace();
		}
	}
}

三、Layui前端框架

1、简介


layui(谐音:类UI) 是一款采用自身模块规范编写的前端 UI 框架,遵循原生 HTML/CSS/JS 的书写与组织形式,门槛极低,拿来即用。其外在极简,却又不失饱满的内在,体积轻盈,组件丰盈,从核心代码到 API 的每一处细节都经过精心雕琢,非常适合界面的快速开发。

layui 首个版本发布于 2016 年金秋,区别于那些基于 MVVM 底层的 UI 框架,却并非逆道而行,而是信奉返璞归真之道。准确地说,更多是为后端程序员量身定做,无需涉足各种前端工具的复杂配置,只需面对浏览器本身,让一切你所需要的元素与交互,从这里信手拈来。

layui 兼容正在使用的全部浏览器(IE6/7除外),可作为 PC 端后台系统与前台界面的速成开发方案。

开发文档地址:https://www.layui.com/doc/

2、使用


(1)通过地址 https://www.layui.com/ 下载layui-v2.5.7的压缩包,将解压后文件夹里的文件夹 layui 放入Web项目文件的WebContent中。

  • layui 的目录结构
├─css //css目录
  │  │─modules //模块css目录(一般如果模块相对较大,我们会单独提取,比如下面三个:)
  │  │  ├─laydate
  │  │  ├─layer
  │  │  └─layim
  │  └─layui.css //核心样式文件
  ├─font  //字体图标目录
  ├─images //图片资源目录(目前只有layim和编辑器用到的GIF表情)
  │─lay //模块核心目录
  │  └─modules //各模块组件
  │─layui.js //基础核心库
  └─layui.all.js //包含layui.js和所有模块的合并文件


(2)在网页文件(html、JSP)中引入 layui 的css文件和js文件。

<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%>
<!-- 加入taglib标记 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<c:set var="basepath" scope="page" value="${pageContext.request.contextPath}"></c:set>
		<!-- 导入layui框架的layui.css -->
		<link href="${basepath}/layui/css/layui.css" rel="stylesheet" media="all">
	</head>
	</body>
		<!-- 导入layui框架的layui.js -->
		<script src="${basepath}/layui/layui.js" charset="utf-8"></script>
	</body>
</html>

(3)使用 layui 模块。

猜你喜欢

转载自blog.csdn.net/qq_42141141/article/details/111939634