|
|
// 声明该类所在的包名为 javabean
|
|
|
package javabean;
|
|
|
|
|
|
// 导入// 声明该类所在的包名为 javabean
|
|
|
package javabean;
|
|
|
|
|
|
// 导入 java.sql 包中的 Connection 类,用于建立与数据库的连接
|
|
|
import java.sql.Connection;
|
|
|
// 导入 java.sql 包中的 PreparedStatement 类,用于执行预编译的 SQL 语句
|
|
|
import java.sql.PreparedStatement;
|
|
|
// 导入 java.sql 包中的 ResultSet 类,用于存储数据库查询结果
|
|
|
import java.sql.ResultSet;
|
|
|
// 导入 java.sql 包中的 SQLException 类,用于处理 SQL 操作中可能出现的异常
|
|
|
import java.sql.SQLException;
|
|
|
|
|
|
// 定义一个名为 Reader 的公共类,用于处理读者登录相关操作
|
|
|
public class Reader {
|
|
|
// 抑制“可能存在空指针引用”的警告
|
|
|
@SuppressWarnings("null")
|
|
|
/**
|
|
|
* 该方法用于处理读者的登录逻辑
|
|
|
* @param user 读者的账号
|
|
|
* @param psw 读者的密码
|
|
|
* @return 返回登录结果的提示信息
|
|
|
* @throws ClassNotFoundException 如果在加载数据库驱动类时出现问题,抛出该异常
|
|
|
* @throws SQLException 如果在执行 SQL 操作时出现问题,抛出该异常
|
|
|
*/
|
|
|
public String login(String user, String psw) throws ClassNotFoundException, SQLException {
|
|
|
|
|
|
// 检查账号是否为空或仅包含空白字符
|
|
|
if (user == null || user.trim().equals("")) {
|
|
|
// 如果账号为空,返回提示信息
|
|
|
return "账号不能为空";
|
|
|
}
|
|
|
// 检查密码是否为空或仅包含空白字符
|
|
|
else if (psw == null || psw.trim().equals("")) {
|
|
|
// 如果密码为空,返回提示信息
|
|
|
return "密码不能为空";
|
|
|
}
|
|
|
|
|
|
// 声明一个 Connection 对象,用于存储与数据库的连接,初始值为 null
|
|
|
Connection connection = null;
|
|
|
// 声明一个 PreparedStatement 对象,用于执行预编译的 SQL 语句,初始值为 null
|
|
|
PreparedStatement pstmt = null;
|
|
|
// 声明一个 ResultSet 对象,用于存储数据库查询结果,初始值为 null
|
|
|
ResultSet resultSet = null;
|
|
|
|
|
|
// 定义一个 SQL 查询语句,使用占位符 ? 来防止 SQL 注入
|
|
|
String sql = "select * from borrow_card where ID=? and PASSWORD=?";
|
|
|
|
|
|
// 调用 Base 类的 getConnection 方法获取数据库连接,并将其赋值给 connection 对象
|
|
|
connection = Base.getConnection();
|
|
|
|
|
|
// 使用 connection 对象创建一个 PreparedStatement 对象,用于执行预编译的 SQL 语句
|
|
|
pstmt = (PreparedStatement) connection.prepareStatement(sql);
|
|
|
|
|
|
// 为 SQL 语句中的第一个占位符(即 ID)设置值,值为传入的 user 参数
|
|
|
pstmt.setString(1, user);
|
|
|
// 为 SQL 语句中的第二个占位符(即 PASSWORD)设置值,值为传入的 psw 参数
|
|
|
pstmt.setString(2, psw);
|
|
|
|
|
|
// 执行 SQL 查询语句,并将查询结果存储在 resultSet 对象中
|
|
|
resultSet = pstmt.executeQuery();
|
|
|
|
|
|
// 检查结果集中是否有下一行记录
|
|
|
if (resultSet.next()) {
|
|
|
// 如果有记录,说明账号和密码匹配,返回 "1" 表示登录成功
|
|
|
return "1";
|
|
|
}
|
|
|
|
|
|
// 如果结果集中没有记录,说明账号或密码错误,返回提示信息
|
|
|
return "账号或密码错误";
|
|
|
}
|
|
|
}
|
|
|
// 声明该 Servlet 类所在的包名为 servlet.reader
|
|
|
package servlet.reader;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.io.PrintWriter;
|
|
|
import java.sql.Connection;
|
|
|
import java.sql.PreparedStatement;
|
|
|
import java.sql.ResultSet;
|
|
|
import java.sql.SQLException;
|
|
|
|
|
|
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 javabean.Base;
|
|
|
import net.sf.json.JSONArray;
|
|
|
import net.sf.json.JSONObject;
|
|
|
|
|
|
/**
|
|
|
* Servlet implementation class Book
|
|
|
* 该 Servlet 用于处理读者相关的书籍查询请求,返回符合条件的书籍信息的 JSON 数据
|
|
|
*/
|
|
|
@WebServlet("/reader/book")
|
|
|
public class Book extends HttpServlet {
|
|
|
// 重写 doGet 方法,处理 HTTP GET 请求
|
|
|
@Override
|
|
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
|
// 设置响应的内容类型为 JSON 格式,并指定字符编码为 UTF-8
|
|
|
resp.setContentType("application/json; charset=utf8");
|
|
|
|
|
|
// 接收客户端传递的参数
|
|
|
// limit 表示每页显示的记录数
|
|
|
String limit = req.getParameter("limit");
|
|
|
// page 表示当前页码
|
|
|
String page = req.getParameter("page");
|
|
|
// condition 表示查询的条件字段
|
|
|
String condition = (String) req.getParameter("condition");
|
|
|
// conditionValue 表示查询条件字段的值
|
|
|
String conditionValue = (String) req.getParameter("conditionValue");
|
|
|
|
|
|
// 初始化 SQL 查询的 WHERE 子句为空,表示无限制条件
|
|
|
String where = "";
|
|
|
|
|
|
// 如果 page 参数为空,默认设置为第 1 页
|
|
|
if (page == null) {
|
|
|
page = "1";
|
|
|
}
|
|
|
// 如果 limit 参数为空,默认设置每页显示 10 条记录
|
|
|
if (limit == null) {
|
|
|
limit = "10";
|
|
|
}
|
|
|
|
|
|
// 准备数据库操作所需的对象
|
|
|
// 数据库连接对象
|
|
|
Connection connection = null;
|
|
|
// 用于执行查询书籍信息的预编译 SQL 语句对象
|
|
|
PreparedStatement pstmt = null;
|
|
|
// 用于执行查询书籍总数的预编译 SQL 语句对象
|
|
|
PreparedStatement countPstmt = null;
|
|
|
// 存储查询书籍信息的结果集
|
|
|
ResultSet resultSet = null;
|
|
|
// 存储查询书籍总数的结果集
|
|
|
ResultSet countSet = null;
|
|
|
// 存储查询书籍信息的 SQL 语句
|
|
|
String sql = "";
|
|
|
// 存储查询书籍总数的 SQL 语句
|
|
|
String countSql = "";
|
|
|
|
|
|
// 准备返回给客户端的参数
|
|
|
// 状态码,1 表示无数据,0 表示查询成功
|
|
|
int code = 1;
|
|
|
// 提示信息,默认提示无数据
|
|
|
String msg = "无数据";
|
|
|
// 符合条件的书籍总数,初始化为 0
|
|
|
int count = 0;
|
|
|
|
|
|
// 用于存储单条书籍信息的 JSON 对象
|
|
|
JSONObject jsonData = new JSONObject();
|
|
|
// 用于存储所有书籍信息的 JSON 数组
|
|
|
JSONArray jsonArray = new JSONArray();
|
|
|
// 用于存储最终返回给客户端的 JSON 数据,包含状态码、总数、提示信息和书籍信息数组
|
|
|
JSONObject jsonResult = new JSONObject();
|
|
|
|
|
|
// 进行数据库查询操作
|
|
|
try {
|
|
|
// 通过 Base 类的 getConnection 方法获取数据库连接
|
|
|
connection = (Connection) Base.getConnection();
|
|
|
// 初始化查询书籍信息的 SQL 语句,从 books 表中查询所有字段
|
|
|
sql = "select * from books ";
|
|
|
// 如果查询条件字段和条件值都不为空,则添加 WHERE 子句到 SQL 语句中
|
|
|
if (condition != null && conditionValue != null && !condition.equals("") && !conditionValue.equals("")) {
|
|
|
where = " where " + condition + " like '%" + conditionValue + "%' ";
|
|
|
sql += where;
|
|
|
}
|
|
|
// 添加分页查询的 LIMIT 子句到 SQL 语句中
|
|
|
sql += " limit ?,?";
|
|
|
// 预编译 SQL 语句
|
|
|
pstmt = connection.prepareStatement(sql);
|
|
|
// 设置 LIMIT 子句的第一个参数,计算当前页的起始记录索引
|
|
|
pstmt.setInt(1, (Integer.parseInt(page) - 1) * Integer.parseInt(limit));
|
|
|
// 设置 LIMIT 子句的第二个参数,即每页显示的记录数
|
|
|
pstmt.setInt(2, Integer.parseInt(limit));
|
|
|
// 执行查询操作,获取结果集
|
|
|
resultSet = pstmt.executeQuery();
|
|
|
|
|
|
// 遍历结果集
|
|
|
while (resultSet.next()) {
|
|
|
// 获取书籍所在图书馆的 ID
|
|
|
String library = resultSet.getString("library_id");
|
|
|
// 构建查询图书馆名称的 SQL 语句
|
|
|
String sql1 = "select * from library where ID =" + library;
|
|
|
// 预编译该 SQL 语句
|
|
|
PreparedStatement pstmt1 = connection.prepareStatement(sql1);
|
|
|
// 执行查询操作,获取结果集
|
|
|
ResultSet rs1 = pstmt1.executeQuery();
|
|
|
// 存储图书馆名称,初始为空
|
|
|
String lib = "";
|
|
|
// 遍历结果集,获取图书馆名称
|
|
|
while (rs1.next()) {
|
|
|
lib = rs1.getString("name");
|
|
|
}
|
|
|
|
|
|
// 获取书籍的分类 ID
|
|
|
String sortid = resultSet.getString("sort_id");
|
|
|
// 构建查询书籍分类名称的 SQL 语句
|
|
|
String sql2 = "select * from book_sort where ID =" + sortid;
|
|
|
// 预编译该 SQL 语句
|
|
|
PreparedStatement pstmt2 = connection.prepareStatement(sql2);
|
|
|
// 执行查询操作,获取结果集
|
|
|
ResultSet rs2 = pstmt2.executeQuery();
|
|
|
// 存储书籍分类名称,初始为空
|
|
|
String sort = "";
|
|
|
// 遍历结果集,获取书籍分类名称
|
|
|
while (rs2.next()) {
|
|
|
sort = rs2.getString("name");
|
|
|
}
|
|
|
|
|
|
// 将书籍信息添加到 JSON 对象中
|
|
|
jsonData.put("id", resultSet.getString("id"));
|
|
|
jsonData.put("name", resultSet.getString("name"));
|
|
|
jsonData.put("author", resultSet.getString("author"));
|
|
|
jsonData.put("library_id", lib);
|
|
|
jsonData.put("sort_id", sort);
|
|
|
jsonData.put("position", resultSet.getString("position"));
|
|
|
jsonData.put("status", resultSet.getString("status"));
|
|
|
jsonData.put("description", resultSet.getString("description"));
|
|
|
// 将单条书籍信息的 JSON 对象添加到 JSON 数组中
|
|
|
jsonArray.add(jsonData);
|
|
|
// 清空 JSON 对象,以便存储下一条书籍信息
|
|
|
jsonData = new JSONObject();
|
|
|
}
|
|
|
|
|
|
// 构建查询书籍总数的 SQL 语句
|
|
|
countSql = "select count(*) as count from books ";
|
|
|
// 添加 WHERE 子句到总数查询的 SQL 语句中
|
|
|
countSql += where;
|
|
|
// 预编译该 SQL 语句
|
|
|
countPstmt = connection.prepareStatement(countSql);
|
|
|
// 执行查询操作,获取结果集
|
|
|
countSet = countPstmt.executeQuery();
|
|
|
// 从结果集中获取书籍总数
|
|
|
if (countSet.next()) {
|
|
|
count = countSet.getInt("count");
|
|
|
}
|
|
|
|
|
|
// 如果 JSON 数组不为空,说明查询到了数据,将状态码设置为 0,提示信息设置为查询成功
|
|
|
if (!jsonArray.isEmpty()) {
|
|
|
code = 0;
|
|
|
msg = "查询成功";
|
|
|
}
|
|
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
// 如果在加载数据库驱动类时出现异常,将提示信息设置为 class 没找到
|
|
|
msg = "class没找到";
|
|
|
} catch (SQLException e) {
|
|
|
// 如果在执行 SQL 语句时出现异常,将提示信息设置为 sql 错误
|
|
|
msg = "sql错误";
|
|
|
} finally {
|
|
|
try {
|
|
|
// 关闭数据库资源,包括 PreparedStatement 和 ResultSet
|
|
|
Base.closeResource(null, pstmt, resultSet);
|
|
|
Base.closeResource(connection, countPstmt, countSet);
|
|
|
} catch (SQLException e) {
|
|
|
// 如果在关闭资源时出现异常,将提示信息设置为关闭资源失败
|
|
|
msg = "关闭资源失败";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 将状态码、总数、提示信息和书籍信息数组添加到最终的 JSON 对象中
|
|
|
jsonResult.put("code", code);
|
|
|
jsonResult.put("count", count);
|
|
|
jsonResult.put("msg", msg);
|
|
|
jsonResult.put("data", jsonArray.toArray());
|
|
|
// 获取响应的输出流
|
|
|
PrintWriter out = resp.getWriter();
|
|
|
// 将最终的 JSON 对象转换为字符串并输出到客户端
|
|
|
out.print(jsonResult.toString());
|
|
|
}
|
|
|
}
|
|
|
// 包声明,表明该类属于servlet.reader包
|
|
|
package servlet.reader;
|
|
|
|
|
|
// 导入处理输入输出异常的类
|
|
|
import java.io.IOException;
|
|
|
// 导入用于向客户端发送字符文本的类
|
|
|
import java.io.PrintWriter;
|
|
|
// 导入表示数据库连接的类
|
|
|
import java.sql.Connection;
|
|
|
// 导入用于执行预编译SQL语句的类
|
|
|
import java.sql.PreparedStatement;
|
|
|
// 导入用于存储数据库查询结果的类
|
|
|
import java.sql.ResultSet;
|
|
|
// 导入处理SQL操作异常的类
|
|
|
import java.sql.SQLException;
|
|
|
|
|
|
// 导入处理Servlet异常的类
|
|
|
import javax.servlet.ServletException;
|
|
|
// 导入用于注解Servlet映射路径的类
|
|
|
import javax.servlet.annotation.WebServlet;
|
|
|
// 导入HttpServlet类,用于创建Servlet
|
|
|
import javax.servlet.http.HttpServlet;
|
|
|
// 导入表示HTTP请求的类
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
// 导入表示HTTP响应的类
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
// 导入用于管理用户会话的类
|
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
|
|
// 导入自定义的数据库连接管理类
|
|
|
import javabean.Base;
|
|
|
// 导入用于处理JSON数组的类
|
|
|
import net.sf.json.JSONArray;
|
|
|
// 导入用于处理JSON对象的类
|
|
|
import net.sf.json.JSONObject;
|
|
|
|
|
|
/**
|
|
|
* Servlet实现类Borrow
|
|
|
* 该Servlet用于处理读者借阅记录的查询请求,返回符合条件的借阅记录的JSON数据
|
|
|
*/
|
|
|
@WebServlet("/reader/borrow")
|
|
|
public class Borrow extends HttpServlet {
|
|
|
// 重写doGet方法,用于处理HTTP GET请求
|
|
|
@Override
|
|
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
|
// 设置响应的内容类型为JSON格式,并指定字符编码为UTF-8
|
|
|
resp.setContentType("application/json; charset=utf8");
|
|
|
|
|
|
// 接收客户端传递的参数
|
|
|
// limit表示每页显示的记录数
|
|
|
String limit = req.getParameter("limit");
|
|
|
// page表示当前页码
|
|
|
String page = req.getParameter("page");
|
|
|
// condition表示查询的条件字段
|
|
|
String condition = (String) req.getParameter("condition");
|
|
|
// conditionValue表示查询条件字段的值
|
|
|
String conditionValue = (String) req.getParameter("conditionValue");
|
|
|
|
|
|
// 初始化SQL查询的WHERE子句为空,表示无限制条件
|
|
|
String where = "";
|
|
|
|
|
|
// 如果page参数为空,默认设置为第1页
|
|
|
if (page == null) {
|
|
|
page = "1";
|
|
|
}
|
|
|
// 如果limit参数为空,默认设置每页显示10条记录
|
|
|
if (limit == null) {
|
|
|
limit = "10";
|
|
|
}
|
|
|
|
|
|
// 准备数据库操作所需的对象
|
|
|
// 数据库连接对象
|
|
|
Connection connection = null;
|
|
|
// 用于执行查询借阅记录的预编译SQL语句对象
|
|
|
PreparedStatement pstmt = null;
|
|
|
// 用于执行查询借阅记录总数的预编译SQL语句对象
|
|
|
PreparedStatement countPstmt = null;
|
|
|
// 存储查询借阅记录的结果集
|
|
|
ResultSet resultSet = null;
|
|
|
// 存储查询借阅记录总数的结果集
|
|
|
ResultSet countSet = null;
|
|
|
// 存储查询借阅记录的SQL语句
|
|
|
String sql = "";
|
|
|
// 存储查询借阅记录总数的SQL语句
|
|
|
String countSql = "";
|
|
|
|
|
|
// 准备返回给客户端的参数
|
|
|
// 状态码,1表示无数据,0表示查询成功
|
|
|
int code = 1;
|
|
|
// 提示信息,默认提示无数据
|
|
|
String msg = "无数据";
|
|
|
// 符合条件的借阅记录总数,初始化为0
|
|
|
int count = 0;
|
|
|
|
|
|
// 获取当前请求的会话对象
|
|
|
HttpSession session = req.getSession();
|
|
|
|
|
|
// 用于存储单条借阅记录信息的JSON对象
|
|
|
JSONObject jsonData = new JSONObject();
|
|
|
// 用于存储所有借阅记录信息的JSON数组
|
|
|
JSONArray jsonArray = new JSONArray();
|
|
|
// 用于存储最终返回给客户端的JSON数据,包含状态码、总数、提示信息和借阅记录信息数组
|
|
|
JSONObject jsonResult = new JSONObject();
|
|
|
|
|
|
// 进行数据库查询操作
|
|
|
try {
|
|
|
// 通过Base类的getConnection方法获取数据库连接
|
|
|
connection = (Connection) Base.getConnection();
|
|
|
// 初始化查询借阅记录的SQL语句,从borrow_books表中查询所有字段,并且只查询当前读者的记录
|
|
|
sql = "select * from borrow_books where card_id = " + session.getAttribute("reader");
|
|
|
// 如果查询条件字段和条件值都不为空,则添加额外的WHERE子句到SQL语句中
|
|
|
if (condition != null && conditionValue != null && !condition.equals("") && !conditionValue.equals("")) {
|
|
|
where = " and " + condition + " like '%" + conditionValue + "%' ";
|
|
|
sql += where;
|
|
|
}
|
|
|
// 添加分页查询的LIMIT子句到SQL语句中
|
|
|
sql += " limit ?,?";
|
|
|
// 打印生成的SQL语句,方便调试
|
|
|
System.out.println("???" + sql);
|
|
|
// 预编译SQL语句
|
|
|
pstmt = connection.prepareStatement(sql);
|
|
|
// 设置LIMIT子句的第一个参数,计算当前页的起始记录索引
|
|
|
pstmt.setInt(1, (Integer.parseInt(page) - 1) * Integer.parseInt(limit));
|
|
|
// 设置LIMIT子句的第二个参数,即每页显示的记录数
|
|
|
pstmt.setInt(2, Integer.parseInt(limit));
|
|
|
// 执行查询操作,获取结果集
|
|
|
resultSet = pstmt.executeQuery();
|
|
|
// 遍历结果集
|
|
|
while (resultSet.next()) {
|
|
|
// 将借阅记录的各个字段信息添加到JSON对象中
|
|
|
jsonData.put("id", resultSet.getString("id"));
|
|
|
jsonData.put("card_id", resultSet.getString("card_id"));
|
|
|
jsonData.put("book_id", resultSet.getString("book_id"));
|
|
|
jsonData.put("borrow_date", resultSet.getString("borrow_date"));
|
|
|
jsonData.put("end_date", resultSet.getString("end_date"));
|
|
|
jsonData.put("return_date", resultSet.getString("return_date"));
|
|
|
// 将单条借阅记录信息的JSON对象添加到JSON数组中
|
|
|
jsonArray.add(jsonData);
|
|
|
// 清空JSON对象,以便存储下一条借阅记录信息
|
|
|
jsonData = new JSONObject();
|
|
|
}
|
|
|
// 构建查询借阅记录总数的SQL语句,同样只查询当前读者的记录
|
|
|
countSql = "select count(*) as count from borrow_books where card_id = "
|
|
|
+ req.getSession().getAttribute("reader");
|
|
|
// 添加额外的WHERE子句到总数查询的SQL语句中
|
|
|
countSql += where;
|
|
|
// 预编译该SQL语句
|
|
|
countPstmt = connection.prepareStatement(countSql);
|
|
|
// 执行查询操作,获取结果集
|
|
|
countSet = countPstmt.executeQuery();
|
|
|
// 从结果集中获取借阅记录总数
|
|
|
if (countSet.next()) {
|
|
|
count = countSet.getInt("count");
|
|
|
}
|
|
|
// 如果JSON数组不为空,说明查询到了数据,将状态码设置为0,提示信息设置为查询成功
|
|
|
if (!jsonArray.isEmpty()) {
|
|
|
code = 0;
|
|
|
msg = "查询成功";
|
|
|
}
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
// 如果在加载数据库驱动类时出现异常,将提示信息设置为class没找到
|
|
|
msg = "class没找到";
|
|
|
} catch (SQLException e) {
|
|
|
// 如果在执行SQL语句时出现异常,将提示信息设置为sql错误
|
|
|
msg = "sql错误";
|
|
|
} finally {
|
|
|
try {
|
|
|
// 关闭数据库资源,包括PreparedStatement和ResultSet
|
|
|
Base.closeResource(null, pstmt, resultSet);
|
|
|
Base.closeResource(connection, countPstmt, countSet);
|
|
|
} catch (SQLException e) {
|
|
|
// 如果在关闭资源时出现异常,将提示信息设置为关闭资源失败
|
|
|
msg = "关闭资源失败";
|
|
|
}
|
|
|
}
|
|
|
// 将状态码、总数、提示信息和借阅记录信息数组添加到最终的JSON对象中
|
|
|
jsonResult.put("code", code);
|
|
|
jsonResult.put("count", count);
|
|
|
jsonResult.put("msg", msg);
|
|
|
jsonResult.put("data", jsonArray.toArray());
|
|
|
// 获取响应的输出流
|
|
|
PrintWriter out = resp.getWriter();
|
|
|
// 将最终的JSON对象转换为字符串并输出到客户端
|
|
|
out.print(jsonResult.toString());
|
|
|
}
|
|
|
}
|
|
|
// 包声明:该Servlet属于servlet.reader包(读者相关Servlet)
|
|
|
package servlet.reader;
|
|
|
|
|
|
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;
|
|
|
|
|
|
/**
|
|
|
* Servlet实现类:退出登录处理
|
|
|
* 功能:处理读者退出登录请求,销毁会话信息并跳转回登录页面
|
|
|
*/
|
|
|
@WebServlet("/reader/exit") // 声明Servlet映射路径:/reader/exit
|
|
|
public class Exit extends HttpServlet {
|
|
|
// 序列化版本号(IDE自动生成,用于保证反序列化兼容性)
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
|
|
// 处理HTTP GET请求(退出操作一般通过GET发起)
|
|
|
@Override
|
|
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
|
|
throws ServletException, IOException {
|
|
|
|
|
|
// 获取当前用户会话
|
|
|
HttpSession session = req.getSession();
|
|
|
|
|
|
// 检查会话中是否存在读者登录信息("reader"为登录时存储的会话属性)
|
|
|
if (session.getAttribute("reader") != null) {
|
|
|
// 移除会话中的读者登录信息,实现退出
|
|
|
session.removeAttribute("reader");
|
|
|
}
|
|
|
|
|
|
// 重定向回读者登录页面(使用动态上下文路径保证部署灵活性)
|
|
|
// req.getContextPath() 获取当前应用的上下文路径(如:/LibrarySystem)
|
|
|
// 跳转目标:/reader/04readerFrame.jsp(读者登录页面)
|
|
|
resp.sendRedirect(req.getContextPath() + "/reader/04readerFrame.jsp");
|
|
|
}
|
|
|
}
|
|
|
// 声明该Servlet类所在的包,用于处理读者相关的Servlet操作
|
|
|
package servlet.reader;
|
|
|
|
|
|
// 导入处理输入输出异常的类
|
|
|
import java.io.IOException;
|
|
|
// 导入用于向客户端发送字符文本的类
|
|
|
import java.io.PrintWriter;
|
|
|
// 导入表示数据库连接的类
|
|
|
import java.sql.Connection;
|
|
|
// 导入用于执行预编译SQL语句的类
|
|
|
import java.sql.PreparedStatement;
|
|
|
// 导入用于存储数据库查询结果的类
|
|
|
import java.sql.ResultSet;
|
|
|
// 导入处理SQL操作异常的类
|
|
|
import java.sql.SQLException;
|
|
|
|
|
|
// 导入处理Servlet异常的类
|
|
|
import javax.servlet.ServletException;
|
|
|
// 导入用于注解Servlet映射路径的类
|
|
|
import javax.servlet.annotation.WebServlet;
|
|
|
// 导入HttpServlet类,用于创建Servlet
|
|
|
import javax.servlet.http.HttpServlet;
|
|
|
// 导入表示HTTP请求的类
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
// 导入表示HTTP响应的类
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
// 导入用于管理用户会话的类
|
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
|
|
// 导入自定义的数据库连接管理类
|
|
|
import javabean.Base;
|
|
|
// 导入用于处理JSON数组的类
|
|
|
import net.sf.json.JSONArray;
|
|
|
// 导入用于处理JSON对象的类
|
|
|
import net.sf.json.JSONObject;
|
|
|
|
|
|
/**
|
|
|
* Servlet实现类Illegal
|
|
|
* 该Servlet用于处理读者违规借阅记录的查询请求,返回符合条件的违规借阅记录的JSON数据
|
|
|
*/
|
|
|
@WebServlet("/reader/illegal")
|
|
|
public class Illegal extends HttpServlet {
|
|
|
// 重写doGet方法,用于处理HTTP GET请求
|
|
|
@Override
|
|
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
|
// 设置响应的内容类型为JSON格式,并指定字符编码为UTF-8
|
|
|
resp.setContentType("application/json; charset=utf8");
|
|
|
|
|
|
// 接收客户端传递的参数
|
|
|
// limit表示每页显示的记录数
|
|
|
String limit = req.getParameter("limit");
|
|
|
// page表示当前页码
|
|
|
String page = req.getParameter("page");
|
|
|
// condition表示查询的条件字段
|
|
|
String condition = (String) req.getParameter("condition");
|
|
|
// conditionValue表示查询条件字段的值
|
|
|
String conditionValue = (String) req.getParameter("conditionValue");
|
|
|
|
|
|
// 初始化SQL查询的WHERE子句为空,表示无限制条件
|
|
|
String where = "";
|
|
|
|
|
|
// 如果page参数为空,默认设置为第1页
|
|
|
if (page == null) {
|
|
|
page = "1";
|
|
|
}
|
|
|
// 如果limit参数为空,默认设置每页显示10条记录
|
|
|
if (limit == null) {
|
|
|
limit = "10";
|
|
|
}
|
|
|
|
|
|
// 准备数据库操作所需的对象
|
|
|
// 数据库连接对象
|
|
|
Connection connection = null;
|
|
|
// 用于执行查询违规借阅记录的预编译SQL语句对象
|
|
|
PreparedStatement pstmt = null;
|
|
|
// 用于执行查询违规借阅记录总数的预编译SQL语句对象
|
|
|
PreparedStatement countPstmt = null;
|
|
|
// 存储查询违规借阅记录的结果集
|
|
|
ResultSet resultSet = null;
|
|
|
// 存储查询违规借阅记录总数的结果集
|
|
|
ResultSet countSet = null;
|
|
|
// 存储查询违规借阅记录的SQL语句
|
|
|
String sql = "";
|
|
|
// 存储查询违规借阅记录总数的SQL语句
|
|
|
String countSql = "";
|
|
|
|
|
|
// 准备返回给客户端的参数
|
|
|
// 状态码,1表示无数据,0表示查询成功
|
|
|
int code = 1;
|
|
|
// 提示信息,默认提示无数据
|
|
|
String msg = "无数据";
|
|
|
// 符合条件的违规借阅记录总数,初始化为0
|
|
|
int count = 0;
|
|
|
|
|
|
// 获取当前请求的会话对象
|
|
|
HttpSession session = req.getSession();
|
|
|
|
|
|
// 用于存储单条违规借阅记录信息的JSON对象
|
|
|
JSONObject jsonData = new JSONObject();
|
|
|
// 用于存储所有违规借阅记录信息的JSON数组
|
|
|
JSONArray jsonArray = new JSONArray();
|
|
|
// 用于存储最终返回给客户端的JSON数据,包含状态码、总数、提示信息和违规借阅记录信息数组
|
|
|
JSONObject jsonResult = new JSONObject();
|
|
|
|
|
|
// 进行数据库查询操作
|
|
|
try {
|
|
|
// 通过Base类的getConnection方法获取数据库连接
|
|
|
connection = (Connection) Base.getConnection();
|
|
|
// 初始化查询违规借阅记录的SQL语句,从borrow_books表中查询所有字段,
|
|
|
// 筛选出违规信息不为空且长度大于0的记录,并且只查询当前读者的记录
|
|
|
sql = "select * from borrow_books where ILLEGAL is not null and length(trim(illegal))>0 AND CARD_ID = "
|
|
|
+ session.getAttribute("reader");
|
|
|
// 如果查询条件字段和条件值都不为空,则添加额外的WHERE子句到SQL语句中
|
|
|
if (condition != null && conditionValue != null && !condition.equals("") && !conditionValue.equals("")) {
|
|
|
where = " and " + condition + " like '%" + conditionValue + "%' ";
|
|
|
sql += where;
|
|
|
}
|
|
|
// 添加分页查询的LIMIT子句到SQL语句中
|
|
|
sql += " limit ?,?";
|
|
|
// 打印生成的SQL语句,方便调试
|
|
|
System.out.println("???" + sql);
|
|
|
// 预编译SQL语句
|
|
|
pstmt = connection.prepareStatement(sql);
|
|
|
// 设置LIMIT子句的第一个参数,计算当前页的起始记录索引
|
|
|
pstmt.setInt(1, (Integer.parseInt(page) - 1) * Integer.parseInt(limit));
|
|
|
// 设置LIMIT子句的第二个参数,即每页显示的记录数
|
|
|
pstmt.setInt(2, Integer.parseInt(limit));
|
|
|
// 执行查询操作,获取结果集
|
|
|
resultSet = pstmt.executeQuery();
|
|
|
// 遍历结果集
|
|
|
while (resultSet.next()) {
|
|
|
// 将违规借阅记录的各个字段信息添加到JSON对象中
|
|
|
jsonData.put("id", resultSet.getString("id"));
|
|
|
jsonData.put("card_id", resultSet.getString("card_id"));
|
|
|
jsonData.put("book_id", resultSet.getString("book_id"));
|
|
|
jsonData.put("borrow_date", resultSet.getString("borrow_date"));
|
|
|
jsonData.put("end_date", resultSet.getString("end_date"));
|
|
|
jsonData.put("return_date", resultSet.getString("return_date"));
|
|
|
jsonData.put("illegal", resultSet.getString("illegal"));
|
|
|
jsonData.put("manager_id", resultSet.getString("manager_id"));
|
|
|
// 将单条违规借阅记录信息的JSON对象添加到JSON数组中
|
|
|
jsonArray.add(jsonData);
|
|
|
// 清空JSON对象,以便存储下一条违规借阅记录信息
|
|
|
jsonData = new JSONObject();
|
|
|
}
|
|
|
// 构建查询违规借阅记录总数的SQL语句,同样筛选出违规信息不为空且长度大于0的记录,
|
|
|
// 并且只查询当前读者的记录
|
|
|
countSql = "select count(*) as count from borrow_books where ILLEGAL is not null and length(trim(illegal))>0 AND CARD_ID = "
|
|
|
+ session.getAttribute("reader");
|
|
|
// 添加额外的WHERE子句到总数查询的SQL语句中
|
|
|
countSql += where;
|
|
|
// 预编译该SQL语句
|
|
|
countPstmt = connection.prepareStatement(countSql);
|
|
|
// 执行查询操作,获取结果集
|
|
|
countSet = countPstmt.executeQuery();
|
|
|
// 从结果集中获取违规借阅记录总数
|
|
|
if (countSet.next()) {
|
|
|
count = countSet.getInt("count");
|
|
|
}
|
|
|
// 如果JSON数组不为空,说明查询到了数据,将状态码设置为0,提示信息设置为查询成功
|
|
|
if (!jsonArray.isEmpty()) {
|
|
|
code = 0;
|
|
|
msg = "查询成功";
|
|
|
}
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
// 如果在加载数据库驱动类时出现异常,将提示信息设置为class没找到
|
|
|
msg = "class没找到";
|
|
|
} catch (SQLException e) {
|
|
|
// 如果在执行SQL语句时出现异常,将提示信息设置为sql错误
|
|
|
msg = "sql错误";
|
|
|
} finally {
|
|
|
try {
|
|
|
// 关闭数据库资源,包括PreparedStatement和ResultSet
|
|
|
Base.closeResource(null, pstmt, resultSet);
|
|
|
Base.closeResource(connection, countPstmt, countSet);
|
|
|
} catch (SQLException e) {
|
|
|
// 如果在关闭资源时出现异常,将提示信息设置为关闭资源失败
|
|
|
msg = "关闭资源失败";
|
|
|
}
|
|
|
}
|
|
|
// 将状态码、总数、提示信息和违规借阅记录信息数组添加到最终的JSON对象中
|
|
|
jsonResult.put("code", code);
|
|
|
jsonResult.put("count", count);
|
|
|
jsonResult.put("msg", msg);
|
|
|
jsonResult.put("data", jsonArray.toArray());
|
|
|
// 获取响应的输出流
|
|
|
PrintWriter out = resp.getWriter();
|
|
|
// 将最终的JSON对象转换为字符串并输出到客户端
|
|
|
out.print(jsonResult.toString());
|
|
|
}
|
|
|
}
|
|
|
// 声明该Servlet类所在的包,用于处理读者相关的Servlet操作
|
|
|
package servlet.reader;
|
|
|
|
|
|
// 导入处理输入输出异常的类
|
|
|
import java.io.IOException;
|
|
|
// 导入用于向客户端发送字符文本的类
|
|
|
import java.io.PrintWriter;
|
|
|
// 导入处理SQL操作异常的类
|
|
|
import java.sql.SQLException;
|
|
|
// 导入HashMap类,用于存储键值对,方便组织响应数据
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
// 导入处理Servlet异常的类
|
|
|
import javax.servlet.ServletException;
|
|
|
// 导入用于注解Servlet映射路径的类
|
|
|
import javax.servlet.annotation.WebServlet;
|
|
|
// 导入HttpServlet类,用于创建Servlet
|
|
|
import javax.servlet.http.HttpServlet;
|
|
|
// 导入表示HTTP请求的类
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
// 导入表示HTTP响应的类
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
// 导入用于管理用户会话的类
|
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
|
|
// 导入自定义的Reader类,用于处理读者登录逻辑
|
|
|
import javabean.Reader;
|
|
|
// 导入用于处理JSON对象的类
|
|
|
import net.sf.json.JSONObject;
|
|
|
|
|
|
/**
|
|
|
* 该Servlet用于处理读者的登录请求。
|
|
|
* 当客户端发送POST请求到 /readerLogin 路径时,会验证读者的账号和密码,
|
|
|
* 并根据验证结果返回相应的JSON数据给客户端。
|
|
|
*/
|
|
|
@WebServlet("/readerLogin")
|
|
|
public class ReaderLogin extends HttpServlet {
|
|
|
|
|
|
/**
|
|
|
* 处理HTTP GET请求。
|
|
|
* 此方法在该Servlet中只是简单地将当前应用的上下文路径返回给客户端,
|
|
|
* 一般登录操作不使用GET请求,这里只是一个默认的处理。
|
|
|
*
|
|
|
* @param request 客户端的HTTP请求对象
|
|
|
* @param response 服务器的HTTP响应对象
|
|
|
* @throws ServletException 如果在处理请求过程中出现Servlet相关的错误
|
|
|
* @throws IOException 如果在输入输出过程中出现错误
|
|
|
*/
|
|
|
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
|
|
throws ServletException, IOException {
|
|
|
response.getWriter().append("Served at: ").append(request.getContextPath());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理HTTP POST请求,实现读者登录功能。
|
|
|
*
|
|
|
* @param request 客户端的HTTP请求对象,包含读者输入的账号和密码
|
|
|
* @param response 服务器的HTTP响应对象,用于返回登录结果的JSON数据
|
|
|
* @throws ServletException 如果在处理请求过程中出现Servlet相关的错误
|
|
|
* @throws IOException 如果在输入输出过程中出现错误
|
|
|
*/
|
|
|
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
|
|
throws ServletException, IOException {
|
|
|
// 设置响应的内容类型为JSON格式,并指定字符编码为UTF-8
|
|
|
response.setContentType("application/json; charset=utf8");
|
|
|
// 获取用于向客户端输出响应内容的PrintWriter对象
|
|
|
PrintWriter out = response.getWriter();
|
|
|
|
|
|
// 从HTTP请求中获取读者输入的账号和密码
|
|
|
String user = request.getParameter("user");
|
|
|
String psw = request.getParameter("psw");
|
|
|
|
|
|
// 创建一个HashMap对象,用于存储要返回给客户端的响应信息,
|
|
|
// 键为字符串类型,值为对象类型
|
|
|
HashMap<String, Object> hashMap = new HashMap<String, Object>();
|
|
|
|
|
|
// 创建Reader类的实例,用于调用登录验证方法
|
|
|
Reader reader = new Reader();
|
|
|
// 用于存储登录验证结果的变量
|
|
|
String result = null;
|
|
|
try {
|
|
|
// 调用Reader类的login方法进行登录验证,传入账号和密码
|
|
|
result = reader.login(user, psw);
|
|
|
} catch (ClassNotFoundException | SQLException e) {
|
|
|
// 捕获可能出现的类未找到异常或SQL异常,并打印异常堆栈信息
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
|
|
|
// 判断登录验证结果是否为 "1","1" 表示登录成功
|
|
|
if (result != null && result.equals("1")) {
|
|
|
// 获取当前请求的会话对象,如果不存在则创建一个新的会话
|
|
|
HttpSession session = request.getSession();
|
|
|
// 将登录的读者账号存储到会话中,方便后续使用
|
|
|
session.setAttribute("reader", user);
|
|
|
// 设置一个标志,表示读者是首次登录(这里假设 "1" 表示登录状态)
|
|
|
session.setAttribute("reader_first", "1");
|
|
|
// 向HashMap中添加登录成功的状态码
|
|
|
hashMap.put("code", 0);
|
|
|
// 向HashMap中添加登录成功的提示信息
|
|
|
hashMap.put("msg", "登录成功");
|
|
|
// 向HashMap中添加登录成功后要跳转的页面URL
|
|
|
hashMap.put("url", request.getContextPath() + "/reader/01main.jsp");
|
|
|
} else {
|
|
|
// 登录失败,向HashMap中添加登录失败的状态码
|
|
|
hashMap.put("code", 1);
|
|
|
// 向HashMap中添加登录失败的提示信息,即登录验证结果中的错误信息
|
|
|
hashMap.put("msg", result);
|
|
|
}
|
|
|
|
|
|
// 将HashMap对象转换为JSON对象
|
|
|
JSONObject json = JSONObject.fromObject(hashMap);
|
|
|
// 将JSON对象转换为字符串并通过PrintWriter输出到客户端
|
|
|
out.write(json.toString());
|
|
|
}
|
|
|
}
|
|
|
<%@ 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 charset="utf-8">
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<title>图书馆欢迎页</title>
|
|
|
|
|
|
<!-- 引入Bootstrap样式 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery(Bootstrap依赖) -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap核心JS -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
|
|
|
<!-- 自定义样式 -->
|
|
|
<style>
|
|
|
/* 轮播图容器样式 */
|
|
|
.showCarousel .carousel-inner > .item > img {
|
|
|
display: block;
|
|
|
width: 100%; /* 图片宽度占满容器 */
|
|
|
height: 620px; /* 固定高度620px */
|
|
|
}
|
|
|
.showCarousel {
|
|
|
margin-top: 2%; /* 轮播图顶部留白2% */
|
|
|
}
|
|
|
/* 字幕文字样式 */
|
|
|
font {
|
|
|
font-size: 40px;
|
|
|
color: black;
|
|
|
font-family: YouYuan; /* 幼圆字体 */
|
|
|
font-weight: 900; /* 加粗 */
|
|
|
}
|
|
|
/* 轮播图字幕位置调整 */
|
|
|
.carousel-caption {
|
|
|
margin-bottom: 10%; /* 底部留白10% */
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
|
|
|
<%-- 会话校验与自动跳转逻辑 --%>
|
|
|
<%
|
|
|
// 检查是否已登录且为首次访问(通过reader_first标记判断)
|
|
|
if (session.getAttribute("reader") != null
|
|
|
&& session.getAttribute("reader_first") != null
|
|
|
&& session.getAttribute("reader_first").equals("1")) {
|
|
|
|
|
|
// 更新标记为已访问(防止重复跳转)
|
|
|
session.setAttribute("reader_first", "2");
|
|
|
|
|
|
// 首次登录时,通过JS跳转至框架页(使用parent.location实现嵌套页面跳转)
|
|
|
%>
|
|
|
<script>window.parent.location.href = "./04readerFrame.jsp";</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
|
|
|
<!-- 轮播图主体 -->
|
|
|
<div id="carousel-example-generic" class="carousel slide showCarousel"
|
|
|
data-ride="carousel" <!-- 启用Bootstrap轮播功能 -->
|
|
|
data-interval="2000" <!-- 自动切换间隔2秒 -->
|
|
|
style="width:96%; margin-left:2%;"> <!-- 容器宽度96%,左侧留白2% -->
|
|
|
|
|
|
<!-- 轮播图指示点(下方小圆点) -->
|
|
|
<ol class="carousel-indicators">
|
|
|
<li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li> <!-- 第1个指示点(默认激活) -->
|
|
|
<li data-target="#carousel-example-generic" data-slide-to="1"></li> <!-- 第2个指示点 -->
|
|
|
<li data-target="#carousel-example-generic" data-slide-to="2"></li> <!-- 第3个指示点 -->
|
|
|
</ol>
|
|
|
|
|
|
<!-- 轮播图图片容器 -->
|
|
|
<div class="carousel-inner" role="listbox">
|
|
|
<!-- 第1张图片(默认激活) -->
|
|
|
<div class="item active">
|
|
|
<img src="../public/image/1.jpg" alt="图书馆全景">
|
|
|
<div class="carousel-caption">
|
|
|
<font style="color:white;">唯有知识永不负你!</font> <!-- 白色字幕 -->
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 第2张图片 -->
|
|
|
<div class="item">
|
|
|
<img src="../public/image/2.jpg" alt="阅读场景">
|
|
|
<div class="carousel-caption">
|
|
|
<font style="color:white;">学海无涯,书韵悠扬</font>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 第3张图片 -->
|
|
|
<div class="item">
|
|
|
<img src="../public/image/3.jpg" alt="书架特写">
|
|
|
<div class="carousel-caption">
|
|
|
<font style="color:white;">图一份神闲气静,书几笔悦目赏心</font>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 轮播图左右控制箭头 -->
|
|
|
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
|
|
|
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span> <!-- 左箭头图标 -->
|
|
|
<span class="sr-only">Previous</span> <!-- 屏幕阅读器文本 -->
|
|
|
</a>
|
|
|
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
|
|
|
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span> <!-- 右箭头图标 -->
|
|
|
<span class="sr-only">Next</span>
|
|
|
</a>
|
|
|
</div>
|
|
|
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ 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 charset="utf-8">
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<title>读者导航栏</title>
|
|
|
|
|
|
<!-- 引入Bootstrap样式 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery(Bootstrap依赖) -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap核心JS(支持导航栏交互) -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
<style>
|
|
|
/* 可扩展:此处可添加导航栏自定义样式 */
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
|
|
|
<!-- 导航栏容器(Bootstrap导航组件) -->
|
|
|
<nav class="navbar navbar-inverse" role="navigation"> <!-- navbar-inverse:深色主题 -->
|
|
|
<div class="container-fluid"> <!-- 流体容器,适应全宽屏幕 -->
|
|
|
|
|
|
<!-- 导航栏头部(用于移动端折叠菜单) -->
|
|
|
<div class="navbar-header">
|
|
|
<!-- 折叠菜单按钮(仅在移动端显示) -->
|
|
|
<button type="button" class="navbar-toggle collapsed"
|
|
|
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
|
|
|
aria-expanded="false">
|
|
|
<span class="sr-only">Toggle navigation</span> <!-- 屏幕阅读器文本 -->
|
|
|
<span class="icon-bar"></span> <!-- 汉堡菜单图标线 -->
|
|
|
<span class="icon-bar"></span>
|
|
|
<span class="icon-bar"></span>
|
|
|
</button>
|
|
|
<!-- 品牌名称(左侧固定显示) -->
|
|
|
<a class="navbar-brand" href="#">欢迎登陆图书管理系统</a>
|
|
|
</div>
|
|
|
|
|
|
<!-- 折叠式导航内容(默认折叠,点击按钮展开) -->
|
|
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
|
|
|
|
|
<!-- 左侧导航项 -->
|
|
|
<ul class="nav navbar-nav">
|
|
|
<!-- 固定显示:借阅者页面标识 -->
|
|
|
<li>
|
|
|
<p style="margin-top:25%;color:grey;">
|
|
|
借阅者页面<span class="sr-only">(current)</span>
|
|
|
</p>
|
|
|
</li>
|
|
|
</ul>
|
|
|
|
|
|
<!-- 右侧导航项(用户状态相关) -->
|
|
|
<ul class="nav navbar-nav navbar-right">
|
|
|
<!-- 用户名显示(登录后可见) -->
|
|
|
<li>
|
|
|
<a href="javascript:;">
|
|
|
<%if(session.getAttribute("reader")==null){ %>
|
|
|
<!-- 未登录时显示空 -->
|
|
|
<%} else{%>
|
|
|
<!-- 已登录时显示用户名 -->
|
|
|
<%=session.getAttribute("reader") %>
|
|
|
<%} %>
|
|
|
</a>
|
|
|
</li>
|
|
|
|
|
|
<!-- 退出/登录按钮(根据会话动态显示) -->
|
|
|
<%if(session.getAttribute("reader") !=null) {%>
|
|
|
<!-- 已登录:显示退出按钮 -->
|
|
|
<li><a href="./exit" target="_parent">退出</a></li>
|
|
|
<%}else{%>
|
|
|
<!-- 未登录:显示登录链接 -->
|
|
|
<li><a href="04readerFrame.jsp" target="_parent">登录</a></li>
|
|
|
<%}%>
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
|
</nav>
|
|
|
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ 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>
|
|
|
<!-- 设置字符编码为UTF-8 -->
|
|
|
<meta charset="utf-8">
|
|
|
<!-- 设置页面在IE浏览器中的渲染模式 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,此处为空 -->
|
|
|
<title></title>
|
|
|
<!-- 引入Bootstrap的CSS文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery库,因为Bootstrap的所有JavaScript插件都依赖jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap的JavaScript文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
<style>
|
|
|
/* 当鼠标悬停在侧边栏的链接上时,设置背景颜色为#337ab7,文字颜色为白色 */
|
|
|
.sidebar li a:hover{
|
|
|
background:#337ab7;
|
|
|
color:white;
|
|
|
}
|
|
|
/* 当侧边栏的链接获得焦点时,设置背景颜色为天蓝色,文字颜色为白色 */
|
|
|
.faq-tabbable li a:focus{
|
|
|
background:skyblue;
|
|
|
color:white;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 创建一个居中的div,宽度和高度都为100%,字体大小为20px(此处原代码冒号使用了中文冒号,应改为英文冒号) -->
|
|
|
<div style="text-align:center;width:100%;height:100%;font-size:20px;">
|
|
|
<!-- 创建一个堆叠式的导航菜单,使用Bootstrap的nav类进行样式设置 -->
|
|
|
<ul class="nav nav-pills nav-stacked nav-inverse sidebar faq-tabbable">
|
|
|
<%
|
|
|
// 检查会话中是否存在"reader"属性,即判断用户是否已登录
|
|
|
if(session.getAttribute("reader")!=null){
|
|
|
%>
|
|
|
<!-- 以下是用户已登录时显示的导航菜单项 -->
|
|
|
<!-- 首页菜单项,点击后在名为view_frame的框架中打开01main.jsp页面 -->
|
|
|
<li role="presentation"><a href="01main.jsp" target="view_frame"><span class="glyphicon glyphicon-picture" aria-hidden="true"> 首页</span></a></li>
|
|
|
<!-- 图书查询菜单项,点击后在名为view_frame的框架中打开05book.jsp页面 -->
|
|
|
<li role="presentation"><a href="05book.jsp" target="view_frame"><span class="glyphicon glyphicon-search" aria-hidden="true"> 图书查询</span></a></li>
|
|
|
<!-- 读者规则菜单项,点击后在名为view_frame的框架中打开12rules.jsp页面 -->
|
|
|
<li role="presentation"><a href="12rules.jsp" target="view_frame"><span class="glyphicon glyphicon-bell" aria-hidden="true"> 读者规则</span></a></li>
|
|
|
<!-- 查看公告菜单项,点击后在名为view_frame的框架中打开07announcement.jsp页面 -->
|
|
|
<li role="presentation"><a href="07announcement.jsp" target="view_frame"><span class="glyphicon glyphicon-bullhorn" aria-hidden="true"> 查看公告</span></a></li>
|
|
|
<!-- 个人信息菜单项,点击后在名为view_frame的框架中打开index.jsp页面 -->
|
|
|
<li role="presentation"><a href="index.jsp" target="view_frame"><span class="glyphicon glyphicon-user" aria-hidden="true"> 个人信息</span></a></li>
|
|
|
<!-- 借阅信息菜单项,点击后在名为view_frame的框架中打开06borrow.jsp页面 -->
|
|
|
<li role="presentation"><a href="06borrow.jsp" target="view_frame"><span class="glyphicon glyphicon-book" aria-hidden="true"> 借阅信息</span></a></li>
|
|
|
<!-- 违章信息菜单项,点击后在名为view_frame的框架中打开08illegalInfo.jsp页面 -->
|
|
|
<li role="presentation"><a href="08illegalInfo.jsp" target="view_frame"><span class="glyphicon glyphicon-remove" aria-hidden="true"> 违章信息</span></a></li>
|
|
|
<!-- 读者留言菜单项,点击后在名为view_frame的框架中打开13message.jsp页面 -->
|
|
|
<li role="presentation"><a href="13message.jsp" target="view_frame"><span class="glyphicon glyphicon-pencil" aria-hidden="true"> 读者留言</span></a></li>
|
|
|
<%
|
|
|
} else {
|
|
|
%>
|
|
|
<!-- 以下是用户未登录时显示的导航菜单项 -->
|
|
|
<!-- 首页菜单项,点击后在名为view_frame的框架中打开01main.jsp页面 -->
|
|
|
<li role="presentation"><a href="01main.jsp" target="view_frame"><span class="glyphicon glyphicon-picture" aria-hidden="true"> 首页</span></a></li>
|
|
|
<!-- 图书查询菜单项,点击后在名为view_frame的框架中打开05book.jsp页面 -->
|
|
|
<li role="presentation"><a href="05book.jsp" target="view_frame"><span class="glyphicon glyphicon-search" aria-hidden="true"> 图书查询</span></a></li>
|
|
|
<!-- 读者规则菜单项,点击后在名为view_frame的框架中打开12rules.jsp页面 -->
|
|
|
<li role="presentation"><a href="12rules.jsp" target="view_frame"><span class="glyphicon glyphicon-bell" aria-hidden="true"> 读者规则</span></a></li>
|
|
|
<!-- 查看公告菜单项,点击后在名为view_frame的框架中打开07announcement.jsp页面 -->
|
|
|
<li role="presentation"><a href="07announcement.jsp" target="view_frame"><span class="glyphicon glyphicon-bullhorn" aria-hidden="true"> 查看公告</span></a></li>
|
|
|
<!-- 查看留言菜单项,点击后在名为view_frame的框架中打开15checkMessage.jsp页面 -->
|
|
|
<li role="presentation"><a href="15checkMessage.jsp" target="view_frame"><span class="glyphicon glyphicon-envelope" aria-hidden="true"> 查看留言</span></a></li>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
</ul>
|
|
|
</div>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ 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>
|
|
|
<!-- 设置字符编码为UTF-8 -->
|
|
|
<meta charset="utf-8">
|
|
|
<!-- 设置页面在IE浏览器中的渲染模式 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,显示为借阅者页面 -->
|
|
|
<title>借阅者页面</title>
|
|
|
|
|
|
<!-- 引入Bootstrap的CSS文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery库,因为Bootstrap的所有JavaScript插件都依赖jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap的JavaScript文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
|
|
|
</head>
|
|
|
<!-- 使用frameset标签将页面划分为多个框架,rows属性指定框架按行划分,这里将页面分为上下两部分,上部分占7%,下部分占剩余空间 -->
|
|
|
<frameset rows="7%,*" frameborder="no" border="0">
|
|
|
<!-- 上半部分框架,src属性指定要加载的页面为02readerNav.jsp,scrolling="no"表示不显示滚动条 -->
|
|
|
<frame src="02readerNav.jsp" scrolling="no">
|
|
|
<!-- 下半部分再使用frameset标签将其划分为左右两部分 -->
|
|
|
<frameset cols="14%,*" frameborder="no" border="0">
|
|
|
<!-- 左半部分框架,src属性指定要加载的页面为03readerNavLeft.jsp -->
|
|
|
<frame src="03readerNavLeft.jsp">
|
|
|
<%
|
|
|
// 检查会话中是否存在"reader"属性,即判断用户是否已登录
|
|
|
if(session.getAttribute("reader") == null){
|
|
|
%>
|
|
|
<!-- 如果用户未登录,将右半部分框架加载06borrow.jsp页面 -->
|
|
|
<frame src="06borrow.jsp" name="view_frame">
|
|
|
<%
|
|
|
} else {
|
|
|
%>
|
|
|
<!-- 如果用户已登录,将右半部分框架加载01main.jsp页面 -->
|
|
|
<frame src="01main.jsp" name="view_frame">
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
</frameset>
|
|
|
</frameset>
|
|
|
</html>
|
|
|
<%@ 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>
|
|
|
<!-- 强制指定页面编码为UTF-8 -->
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
|
<!-- 页面标题(未设置,可根据功能补充) -->
|
|
|
<title>图书查询管理</title>
|
|
|
|
|
|
<!-- 响应式布局元标签 -->
|
|
|
<meta charset="utf-8">
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
|
|
<!-- 引入前端框架资源 -->
|
|
|
<!-- Bootstrap基础样式 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- Bootstrap表格扩展样式 -->
|
|
|
<link href="../css/bootstrap-table.css" rel="stylesheet">
|
|
|
<!-- jQuery库(前端交互基础) -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- Bootstrap表格功能 -->
|
|
|
<script src="../js/bootstrap-table.js"></script>
|
|
|
<!-- 表格中文语言包 -->
|
|
|
<script src="../bootstrap-table-zh-CN.js"></script>
|
|
|
<!-- LayUI框架(国产UI组件库,用于弹窗、表格等) -->
|
|
|
<link rel="stylesheet" href="../public/layui/css/layui.css" media="all">
|
|
|
<style>
|
|
|
/* 自定义LayUI表格样式 */
|
|
|
.layui-table, .layui-table-view {
|
|
|
margin: 0 0px; /* 移除表格默认外边距 */
|
|
|
}
|
|
|
/* 下拉框选中项颜色(匹配系统主题) */
|
|
|
.layui-form-select dl dd.layui-this { background-color: #01AAED; }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 声明JavaBean:用于数据库操作(作用域:会话级) -->
|
|
|
<jsp:useBean id="msg" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
|
|
|
<!-- 引入LayUI核心脚本 -->
|
|
|
<script src="../public/layui/layui.js" charset="utf-8"></script>
|
|
|
|
|
|
<!-- 表格容器(LayUI隐藏容器,渲染后显示) -->
|
|
|
<table class="layui-hide" id="cardTable" lay-filter="formFilter"></table>
|
|
|
|
|
|
<!-- 头部工具栏模板(使用LayUI的script模板语法) -->
|
|
|
<script type="text/html" id="headBar">
|
|
|
条件搜索:
|
|
|
<div class="layui-inline">
|
|
|
<!-- 搜索条件下拉框 -->
|
|
|
<select id="condition" name="condition" lay-verify="required">
|
|
|
<option value=""></option>
|
|
|
<option value="id">图书编号</option>
|
|
|
<option value="name">图书名称</option>
|
|
|
<option value="author">作者</option>
|
|
|
<option value="position">位置</option>
|
|
|
<option value="description">描述</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
<div class="layui-inline">
|
|
|
<!-- 搜索关键词输入框 -->
|
|
|
<input class="layui-input" id="conditionValue" name="conditionValue" autocomplete="off">
|
|
|
</div>
|
|
|
<!-- 搜索按钮(绑定LayUI事件) -->
|
|
|
<button class="layui-btn layui-bg-blue" data-type="reload" lay-event="search">搜索</button>
|
|
|
</script>
|
|
|
|
|
|
<script>
|
|
|
layui.use(['table', 'jquery'], function () {
|
|
|
var $ = layui.jquery,
|
|
|
table = layui.table;
|
|
|
|
|
|
// 1. 表格初始化渲染
|
|
|
var tableIns = table.render({
|
|
|
elem: '#cardTable', // 绑定表格容器
|
|
|
url: './book', // 数据接口(对应Book Servlet)
|
|
|
toolbar: '#headBar', // 绑定头部工具栏模板
|
|
|
cols: [[ // 表格列配置
|
|
|
{field: 'id', width: 120, title: '图书编号', sort: true},
|
|
|
{field: 'name', width: 130, title: '图书名称', sort: true},
|
|
|
{field: 'author', width: 100, title: '作者', sort: true},
|
|
|
{field: 'library_id', title: '图书馆', width: 100, sort: true},
|
|
|
{field: 'sort_id', width: 100, title: '分类', sort: true},
|
|
|
{field: 'position', width: 100, title: '位置', sort: true},
|
|
|
{field: 'status', width: 100, title: '状态', sort: true,
|
|
|
// 状态字段模板:根据值显示不同颜色
|
|
|
templet: function (item) {
|
|
|
return item.status === '0' ?
|
|
|
'<span style="color:orange">已借出</span>' :
|
|
|
'<span style="color:green">未借出</span>';
|
|
|
}
|
|
|
},
|
|
|
{field: 'description', minWidth: 80, title: '描述'}
|
|
|
]],
|
|
|
page: { // 分页配置
|
|
|
theme: '#2F88FF', // 分页条颜色
|
|
|
layout: ['count', 'prev', 'page', 'next', 'limit']
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 2. 头部工具栏事件处理
|
|
|
table.on('toolbar(formFilter)', function (obj) {
|
|
|
var checkStatus = table.checkStatus(obj.config.id);
|
|
|
switch (obj.event) {
|
|
|
case 'search':
|
|
|
// 获取搜索条件
|
|
|
var condition = $('#condition').val(),
|
|
|
conditionValue = $('#conditionValue').val();
|
|
|
|
|
|
// 重载表格(触发Book Servlet重新查询)
|
|
|
tableIns.reload({
|
|
|
where: {
|
|
|
condition: condition,
|
|
|
conditionValue: conditionValue
|
|
|
},
|
|
|
page: { curr: 1 } // 重置为第一页
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
case 'add':
|
|
|
// 弹出添加图书弹窗(layer框架)
|
|
|
layer.open({
|
|
|
type: 2,
|
|
|
title: '添加图书',
|
|
|
area: ['800px', '500px'],
|
|
|
content: 'cardadd.jsp' // 跳转到添加页面
|
|
|
});
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 3. 行工具事件处理(编辑等)
|
|
|
table.on('tool(formFilter)', function (obj) {
|
|
|
var data = obj.data,
|
|
|
layEvent = obj.event;
|
|
|
|
|
|
switch (layEvent) {
|
|
|
case 'edit':
|
|
|
// 弹出编辑弹窗(需补充具体URL)
|
|
|
layer.open({
|
|
|
type: 2,
|
|
|
title: '编辑图书',
|
|
|
area: ['800px', '600px'],
|
|
|
content: '' // 待补充编辑页面路径
|
|
|
});
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ 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>
|
|
|
<!-- 设置页面内容类型和字符编码为UTF-8 -->
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
|
<!-- 页面标题,可根据实际情况修改 -->
|
|
|
<title>Insert title here</title>
|
|
|
<!-- 引入Bootstrap的CSS文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入Bootstrap表格的CSS文件,用于表格样式 -->
|
|
|
<link href="../css/bootstrap-table.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery库,因为Bootstrap的所有JavaScript插件都依赖jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap表格的JavaScript文件,用于实现表格功能 -->
|
|
|
<script src="../js/bootstrap-table.js"></script>
|
|
|
<!-- 引入Bootstrap表格的中文语言包 -->
|
|
|
<script src="../bootstrap-table-zh-CN.js"></script>
|
|
|
<!-- 引入Layui框架的CSS文件,用于页面样式 -->
|
|
|
<link rel="stylesheet" href="../public/layui/css/layui.css" media="all">
|
|
|
<style>
|
|
|
/* 设置Layui表格和表格视图的外边距为0 */
|
|
|
.layui-table,.layui-table-view{
|
|
|
margin: 0 0px;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 引入Layui框架的JavaScript文件 -->
|
|
|
<script src="../public/layui/layui.js" charset="utf-8"></script>
|
|
|
<!-- 表单 -->
|
|
|
<%
|
|
|
// 检查会话中是否存在"reader"属性,若不存在则表示用户未登录
|
|
|
if(session.getAttribute("reader")==null){%>
|
|
|
<script>
|
|
|
// 若用户未登录,将页面重定向到登录页面
|
|
|
location.href = "../loginReader.html";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
<!-- 创建一个隐藏的表格,用于后续Layui表格渲染 -->
|
|
|
<table class="layui-hide" id="cardTable" lay-filter="formFilter"></table>
|
|
|
|
|
|
<!-- 头部工具栏模板 -->
|
|
|
<script type="text/html" id="headBar">
|
|
|
条件搜索:
|
|
|
<div class="layui-inline">
|
|
|
<!-- 条件选择下拉框 -->
|
|
|
<select id="condition" name="condition" lay-verify="required">
|
|
|
<option value=""></option>
|
|
|
<option value="book_id">图书编号</option>
|
|
|
<option value="borrow_date">借阅日期</option>
|
|
|
<option value="end_date">截止日期</option>
|
|
|
<option value="return_date">归还日期</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
<div class="layui-inline">
|
|
|
<!-- 条件值输入框 -->
|
|
|
<input class="layui-input" id="conditionValue" name="conditionValue" id="demoReload" autocomplete="off">
|
|
|
</div>
|
|
|
<!-- 搜索按钮,点击触发搜索事件 -->
|
|
|
<button class="layui-btn" name="condition" data-type="reload" lay-event="search">搜索</button>
|
|
|
</script>
|
|
|
|
|
|
<script>
|
|
|
// 使用Layui的use方法加载table和jquery模块
|
|
|
layui.use(['table','jquery'], function(){
|
|
|
// 获取jQuery对象
|
|
|
$ = layui.jquery;
|
|
|
// 获取Layui的table模块
|
|
|
var table = layui.table;
|
|
|
// 进行表格渲染
|
|
|
var tableIns = table.render({
|
|
|
// 绑定表格渲染的目标元素
|
|
|
elem: '#cardTable',
|
|
|
// 表格数据的请求URL,对应后端处理借阅记录查询的Servlet
|
|
|
url:'./borrow',
|
|
|
// 绑定头部工具栏模板
|
|
|
toolbar: '#headBar',
|
|
|
// 表格列配置
|
|
|
cols: [[
|
|
|
// 借阅证号列
|
|
|
{field:'card_id', width:180, title: '借阅证号', sort: true},
|
|
|
// 图书编号列
|
|
|
{field:'book_id', width:130, title: '图书编号', sort: true},
|
|
|
// 借阅日期列
|
|
|
{field:'borrow_date', width:250, title: '借阅日期', sort: true},
|
|
|
// 截止日期列
|
|
|
{field:'end_date', title: '截止日期', width: 250, sort: true},
|
|
|
// 归还时间列
|
|
|
{field:'return_date', width:250, title: '归还时间', sort: true}
|
|
|
]],
|
|
|
// 开启分页功能
|
|
|
page: true
|
|
|
});
|
|
|
|
|
|
// 监听头部工具栏事件
|
|
|
table.on('toolbar(formFilter)', function(obj){
|
|
|
// 获取表格的选中状态
|
|
|
var checkStatus = table.checkStatus(obj.config.id);
|
|
|
switch(obj.event){
|
|
|
// 条件查找借阅记录
|
|
|
case 'search':
|
|
|
// 获取条件值输入框的元素
|
|
|
var conditionValue = $('#conditionValue');
|
|
|
// 获取条件选择下拉框的元素
|
|
|
var condition = $('#condition');
|
|
|
|
|
|
// 进行搜索,重新渲染表格
|
|
|
tableIns.reload({
|
|
|
where: {
|
|
|
// 设定异步数据接口的额外参数,传递搜索条件和条件值
|
|
|
"condition": condition.val(),
|
|
|
"conditionValue": conditionValue.val()
|
|
|
},
|
|
|
page: {
|
|
|
// 重新从第1页开始
|
|
|
curr: 1
|
|
|
}
|
|
|
});
|
|
|
break;
|
|
|
case 'add':
|
|
|
// 弹出添加借书证的弹窗
|
|
|
var addCardLayer = layer.open({
|
|
|
type: 2,
|
|
|
title: '添加借书证',
|
|
|
area: ['800px', '500px'],
|
|
|
maxmin: true,
|
|
|
shadeClose: true,
|
|
|
// 弹窗内容的页面路径
|
|
|
content: 'cardadd.jsp',
|
|
|
});
|
|
|
// 可将弹窗设置为全屏显示,此处注释掉了
|
|
|
// layer.full(addCardLayer);
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 监听侧边工具栏事件
|
|
|
table.on('tool(formFilter)', function(obj){
|
|
|
// 获取当前行的数据
|
|
|
var data = obj.data;
|
|
|
// 获取当前触发的事件名
|
|
|
var layEvent = obj.event;
|
|
|
// 获取当前行的DOM元素
|
|
|
var tr = obj.tr;
|
|
|
switch(obj.event){
|
|
|
case 'edit':
|
|
|
// 弹出更改信息的弹窗
|
|
|
layer.open({
|
|
|
type: 2,
|
|
|
title: '更改信息',
|
|
|
area: ['800px', '600px'],
|
|
|
maxmin: true,
|
|
|
shadeClose: true,
|
|
|
// 弹窗内容的页面路径,此处为空,需要补充
|
|
|
content: '',
|
|
|
});
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ page import="java.sql.*" %>
|
|
|
<%@ 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>
|
|
|
<!-- 设置字符编码为UTF-8 -->
|
|
|
<meta charset="utf-8">
|
|
|
<!-- 设置页面在IE浏览器中的渲染模式 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,此处为空 -->
|
|
|
<title></title>
|
|
|
<!-- 引入Bootstrap的CSS文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery库,因为Bootstrap的所有JavaScript插件都依赖jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap的JavaScript文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
<style>
|
|
|
/* 设置页面主体的字体为幼圆 */
|
|
|
body{
|
|
|
font-family:YouYuan;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 创建一个背景颜色为钢蓝色,高度为30px,文字颜色为白色,圆角半径为8px,宽度为页面宽度90%且居中显示的div -->
|
|
|
<div style="background: steelblue;height: 30px;;color:#fff;border-radius: 8px;width: 90%;margin:auto auto;">
|
|
|
<!-- 创建一个滚动字幕,文字大小为20px,字体为幼圆,向左滚动,水平和垂直间距为0.1%,无限循环,滚动速度为20,滚动延迟为100 -->
|
|
|
<!-- 鼠标悬停时滚动停止,鼠标移开时继续滚动 -->
|
|
|
<marquee style="font-size:20px;font-family:YouYuan;" behavior="scroll" direction="left" hspace="0.1%" vspace="0.1%" loop="-1" scrollamount="20" scrolldelay="100" onMouseOut="this.start()" onMouseOver="this.stop()">
|
|
|
❤图书馆公告栏,记得查收公告呀!❤
|
|
|
</marquee>
|
|
|
</div>
|
|
|
|
|
|
<!-- 创建一个居中对齐的div -->
|
|
|
<div class="a" align="center">
|
|
|
<!-- 显示标题“近期公告” -->
|
|
|
<h2>近期公告</h2>
|
|
|
|
|
|
<!-- 使用JSP的useBean标签创建一个名为check的JavaBean实例,作用域为会话级别,类名为javabean.JDBCBean -->
|
|
|
<jsp:useBean id="check" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
<%
|
|
|
// 定义SQL查询语句,从announcement表中查询所有记录
|
|
|
String sql="select*from announcement";
|
|
|
// 调用JavaBean的executeQuery方法执行SQL查询,并将结果存储在ResultSet对象中
|
|
|
ResultSet rs = check.executeQuery(sql);
|
|
|
// 遍历ResultSet对象,处理每一条查询结果
|
|
|
while (rs.next()) {
|
|
|
%>
|
|
|
<!-- 创建一个Bootstrap的面板组件,样式为信息面板,左边距为5%,宽度为80% -->
|
|
|
<div class="panel panel-info" style="margin-left:5%;width:80%;">
|
|
|
<!-- 面板头部,居中对齐 -->
|
|
|
<div class="panel-heading" align="center">
|
|
|
<!-- 显示公告的标题 -->
|
|
|
<span><%=rs.getString("TITLE") %></span>
|
|
|
<!-- 显示公告的发布日期,右边距为1% -->
|
|
|
<span style="margin-right:1%;"><%=rs.getString("PUBLISH_DATE") %></span>
|
|
|
</div>
|
|
|
<!-- 面板主体 -->
|
|
|
<div class="panel-body" >
|
|
|
<!-- 显示公告的详细内容,设置文字换行 -->
|
|
|
<p style="word-wrap:break-word;"><%=rs.getString("DETAIL") %></p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
</div>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ 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=UTF-8">
|
|
|
<!-- 页面标题,可根据实际情况修改 -->
|
|
|
<title>Insert title here</title>
|
|
|
<!-- 引入Bootstrap的基础CSS文件,用于页面布局和样式 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入Bootstrap表格的CSS文件,用于美化表格样式 -->
|
|
|
<link href="../css/bootstrap-table.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery库,因为Bootstrap的JavaScript插件依赖于它 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap表格的JavaScript文件,用于实现表格的交互功能 -->
|
|
|
<script src="../js/bootstrap-table.js"></script>
|
|
|
<!-- 引入Bootstrap表格的中文语言包,使表格提示信息显示为中文 -->
|
|
|
<script src="../bootstrap-table-zh-CN.js"></script>
|
|
|
<!-- 引入Layui框架的CSS文件,用于页面的样式和组件 -->
|
|
|
<link rel="stylesheet" href="../public/layui/css/layui.css" media="all">
|
|
|
<!-- 重复引入Layui框架的CSS文件,可删除重复部分 -->
|
|
|
<link rel="stylesheet" href="../public/layui/css/layui.css" media="all">
|
|
|
<style>
|
|
|
/* 设置Layui表格和表格视图的外边距为0 */
|
|
|
.layui-table,.layui-table-view{
|
|
|
margin: 0 0px;
|
|
|
}
|
|
|
/* 设置Layui表单下拉框中选中项的背景颜色为橙色 */
|
|
|
.layui-form-select dl dd.layui-this { background-color: #FF5722; }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<%
|
|
|
// 检查会话中是否存在 "reader" 属性,如果不存在则表示用户未登录
|
|
|
if(session.getAttribute("reader") == null){
|
|
|
%>
|
|
|
<script>
|
|
|
// 如果用户未登录,将页面重定向到登录页面
|
|
|
location.href="../loginReader.html";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
<!-- 引入Layui框架的JavaScript文件 -->
|
|
|
<script src="../public/layui/layui.js" charset="utf-8"></script>
|
|
|
<!-- 创建一个隐藏的表格,用于后续Layui表格的渲染 -->
|
|
|
<table class="layui-hide" id="cardTable" lay-filter="formFilter"></table>
|
|
|
|
|
|
<!-- 定义头部工具栏的模板 -->
|
|
|
<script type="text/html" id="headBar">
|
|
|
条件搜索:
|
|
|
<div class="layui-inline">
|
|
|
<!-- 创建一个下拉框,用于选择搜索条件 -->
|
|
|
<select id="condition" name="condition" lay-verify="required">
|
|
|
<option value=""></option>
|
|
|
<option value="book_id">图书编号</option>
|
|
|
<option value="borrow_date">借阅日期</option>
|
|
|
<option value="end_date">截止日期</option>
|
|
|
<option value="return_date">归还日期</option>
|
|
|
<option value="illegal">违章信息</option>
|
|
|
<option value="manager_id">处理人</option>
|
|
|
</select>
|
|
|
</div>
|
|
|
<div class="layui-inline">
|
|
|
<!-- 创建一个输入框,用于输入搜索条件的值 -->
|
|
|
<input class="layui-input" id="conditionValue" name="conditionValue" id="demoReload" autocomplete="off">
|
|
|
</div>
|
|
|
<!-- 创建一个红色按钮,点击触发搜索事件 -->
|
|
|
<button class="layui-btn layui-btn-danger" name="condition" data-type="reload" lay-event="search">搜索</button>
|
|
|
</script>
|
|
|
|
|
|
<script>
|
|
|
// 使用Layui的use方法加载 table 和 jquery 模块
|
|
|
layui.use(['table','jquery'], function(){
|
|
|
// 获取 jQuery 对象
|
|
|
$ = layui.jquery;
|
|
|
// 获取 Layui 的 table 模块
|
|
|
var table = layui.table;
|
|
|
// 渲染表格
|
|
|
var tableIns = table.render({
|
|
|
// 绑定表格渲染的目标元素
|
|
|
elem: '#cardTable',
|
|
|
// 表格数据的请求 URL,对应后端处理违章信息查询的 Servlet
|
|
|
url:'./illegal',
|
|
|
// 绑定头部工具栏的模板
|
|
|
toolbar: '#headBar',
|
|
|
// 定义表格的列
|
|
|
cols: [[
|
|
|
// 借阅证号列,宽度为 180px,可排序
|
|
|
{field:'card_id', width:180, title: '借阅证号', sort: true},
|
|
|
// 图书编号列,最小宽度为 80px,可排序
|
|
|
{field:'book_id', minwidth:80, title: '图书编号', sort: true},
|
|
|
// 借阅日期列,宽度为 250px,可排序
|
|
|
{field:'borrow_date', width:250, title: '借阅日期', sort: true},
|
|
|
// 截止日期列,宽度为 250px,可排序
|
|
|
{field:'end_date', title: '截止日期', width: 250, sort: true},
|
|
|
// 归还时间列,宽度为 250px,可排序
|
|
|
{field:'return_date', width:250, title: '归还时间', sort: true},
|
|
|
// 违章信息列,宽度为 180px,可排序,文字颜色为红色
|
|
|
{field:'illegal', width:180, title: '违章信息', sort: true,style:'color: red;'},
|
|
|
// 处理人列,宽度为 90px,可排序
|
|
|
{field:'manager_id', width:90, title: '处理人', sort: true}
|
|
|
]],
|
|
|
// 开启分页功能
|
|
|
page: true,
|
|
|
// 设置分页条的主题颜色为橙色
|
|
|
page: {theme: '#FF5722'},
|
|
|
});
|
|
|
|
|
|
// 监听头部工具栏的事件
|
|
|
table.on('toolbar(formFilter)', function(obj){
|
|
|
// 获取表格的选中状态
|
|
|
var checkStatus = table.checkStatus(obj.config.id);
|
|
|
switch(obj.event){
|
|
|
// 处理搜索事件
|
|
|
case 'search':
|
|
|
// 获取输入框中的搜索条件值
|
|
|
var conditionValue = $('#conditionValue');
|
|
|
// 获取下拉框中选择的搜索条件
|
|
|
var condition = $('#condition');
|
|
|
|
|
|
// 重新加载表格数据,传递搜索条件和条件值
|
|
|
tableIns.reload({
|
|
|
where: {
|
|
|
// 设定异步数据接口的额外参数
|
|
|
"condition": condition.val(),
|
|
|
"conditionValue": conditionValue.val()
|
|
|
},
|
|
|
page: {
|
|
|
// 重新从第 1 页开始
|
|
|
curr: 1
|
|
|
}
|
|
|
});
|
|
|
break;
|
|
|
// 处理添加借书证事件
|
|
|
case 'add':
|
|
|
// 弹出一个层,用于添加借书证
|
|
|
var addCardLayer = layer.open({
|
|
|
type: 2,
|
|
|
title: '添加借书证',
|
|
|
area: ['800px', '500px'],
|
|
|
maxmin: true,
|
|
|
shadeClose: true,
|
|
|
// 层的内容为 cardadd.jsp 页面
|
|
|
content: 'cardadd.jsp',
|
|
|
});
|
|
|
// 可将层设置为全屏显示,此处注释掉了
|
|
|
// layer.full(addCardLayer);
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 监听表格行工具的事件
|
|
|
table.on(('tool(formFilter)'), function(obj){
|
|
|
// 获取当前行的数据
|
|
|
var data = obj.data;
|
|
|
// 获取当前触发的事件名
|
|
|
var layEvent = obj.event;
|
|
|
// 获取当前行的 DOM 元素
|
|
|
var tr = obj.tr;
|
|
|
switch(obj.event){
|
|
|
// 处理编辑事件
|
|
|
case 'edit':
|
|
|
// 弹出一个层,用于更改信息
|
|
|
layer.open({
|
|
|
type: 2,
|
|
|
title: '更改信息',
|
|
|
area: ['800px', '600px'],
|
|
|
maxmin: true,
|
|
|
shadeClose: true,
|
|
|
// 层的内容为空,需要补充具体的页面路径
|
|
|
content: '',
|
|
|
});
|
|
|
break;
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ page import="java.sql.*"%>
|
|
|
<%@ page import="java.util.*"%>
|
|
|
<%@ 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=UTF-8">
|
|
|
<!-- 页面标题,显示为修改密码 -->
|
|
|
<title>修改密码</title>
|
|
|
<!-- 引入toastr的JavaScript文件,toastr是一个用于显示通知消息的插件 -->
|
|
|
<script src="${ctx}/toastr/toastr.min.js"></script>
|
|
|
<!-- 引入toastr的CSS文件,用于设置通知消息的样式 -->
|
|
|
<link rel="stylesheet" href="${ctx}/toastr/toastr.min.css">
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 使用JSP的useBean标签创建一个名为check的JavaBean实例,作用域为会话级别,类名为javabean.JDBCBean -->
|
|
|
<jsp:useBean id="check" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
<%
|
|
|
// 从请求中获取用户输入的新密码(第一次输入)
|
|
|
String psw1 = request.getParameter("psw1");
|
|
|
// 从请求中获取用户输入的新密码(第二次输入)
|
|
|
String psw2 = request.getParameter("psw2");
|
|
|
|
|
|
// 输出两次输入的密码,用于调试,此处注释掉了
|
|
|
//out.println(psw1 + " " + psw2);
|
|
|
|
|
|
// 从会话中获取当前登录读者的ID,并将其转换为字符串类型
|
|
|
String id = session.getAttribute("reader").toString();
|
|
|
|
|
|
// 检查两次输入的密码是否相同,且不为空或仅包含空格
|
|
|
if (psw1.equals(psw2) && psw1 != null && psw2 != null && !psw1.trim().equals("")
|
|
|
&& !psw2.trim().equals("")) {
|
|
|
// 构建SQL更新语句,将borrow_card表中对应ID的用户密码更新为新密码
|
|
|
String sql = "update borrow_card set PASSWORD ='" + psw1 + "' where ID=" + id;
|
|
|
try {
|
|
|
// 调用JavaBean的executeUpdate方法执行SQL更新语句,并获取受影响的行数
|
|
|
int i = check.executeUpdate(sql);
|
|
|
// 判断受影响的行数是否为1,即是否成功更新了一条记录
|
|
|
if (i == 1) {
|
|
|
%>
|
|
|
<!-- 如果修改成功,弹出提示框告知用户,并将页面重定向到index.jsp -->
|
|
|
<script>
|
|
|
alert('修改成功!');
|
|
|
window.location.href = "index.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
} else {
|
|
|
%>
|
|
|
<!-- 如果修改未成功,弹出提示框告知用户,并将页面重定向到index.jsp -->
|
|
|
<script>
|
|
|
alert('修改未成功!');
|
|
|
window.location.href = "index.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
%>
|
|
|
<!-- 如果执行SQL语句时出现异常,弹出提示框告知用户,并将页面重定向到index.jsp -->
|
|
|
<script>
|
|
|
alert('修改未成功!');
|
|
|
window.location.href = "index.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
} else {
|
|
|
%>
|
|
|
<!-- 如果两次输入的密码不相同或为空,弹出提示框告知用户,并将页面重定向到index.jsp -->
|
|
|
<script>
|
|
|
alert('修改未成功!');
|
|
|
window.location.href = "index.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ page import="java.sql.*" %>
|
|
|
<%@ page import="java.util.*" %>
|
|
|
<%@ 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>
|
|
|
<!-- 设置字符编码为UTF-8 -->
|
|
|
<meta charset="utf-8">
|
|
|
<!-- 设置页面在IE浏览器中的渲染模式 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,此处为空 -->
|
|
|
<title></title>
|
|
|
<!-- 引入Bootstrap的CSS文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入jQuery库,因为Bootstrap的所有JavaScript插件都依赖jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入Bootstrap的JavaScript文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
<!-- 引入自定义的消息样式文件 -->
|
|
|
<link rel="stylesheet" id="templatecss" type="text/css" href="../public/css/message.css">
|
|
|
<style>
|
|
|
/* 设置页面主体的背景颜色为白色,文字颜色为黑色 */
|
|
|
body{
|
|
|
background-color:#fff;
|
|
|
color:black;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<script>
|
|
|
// 文档加载完成后,初始化所有带有data-toggle="popover"属性的元素为弹出框
|
|
|
$(function () {
|
|
|
$("[data-toggle='popover']").popover();
|
|
|
});
|
|
|
</script>
|
|
|
<!-- 使用JSP的useBean标签创建一个名为msg的JavaBean实例,作用域为会话级别,类名为javabean.JDBCBean -->
|
|
|
<jsp:useBean id="msg" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
<!-- 创建一个居中对齐的div,显示标题 -->
|
|
|
<div align="center"><h1 style="color:steelblue;font-family:YouYuan;font-weight:900;">读者规则信息查看</h1></div>
|
|
|
<!-- 创建一个居中对齐的div,设置上边距为5% -->
|
|
|
<div style="margin-top:5%;" align="center">
|
|
|
<%
|
|
|
// 定义SQL查询语句,从rules表中查询所有记录
|
|
|
String sql = "select * from rules";
|
|
|
// 调用JavaBean的executeQuery方法执行SQL查询,并将结果存储在ResultSet对象中
|
|
|
ResultSet rs = msg.executeQuery(sql);
|
|
|
// 遍历ResultSet对象,处理每一条查询结果
|
|
|
while (rs.next()) {
|
|
|
// 判断借阅证规则编号是否为奇数
|
|
|
if(Integer.parseInt(rs.getString("ID")) % 2== 1){
|
|
|
%>
|
|
|
<!-- 创建一个蓝色按钮,当鼠标悬停或点击时弹出提示框 -->
|
|
|
<button type="button" class="btn btn-lg btn-info"
|
|
|
title="可借阅数量:<%=rs.getString("BORROW_NUM") %>"
|
|
|
data-html="true"
|
|
|
data-container="body"
|
|
|
data-trigger="focus"
|
|
|
data-toggle="popover"
|
|
|
data-placement="left"
|
|
|
data-content="可借阅天数:<%=rs.getString("LIMIT_DAY") %><br>可借阅图书馆:<%=rs.getString("BORROW_LIBRARY") %><br>过期扣费/天:<%=rs.getString("OVERTIME_FEE") %>"
|
|
|
style="width:40%;height:100%;font-size:17px;margin-top:4%;">
|
|
|
<!-- 显示借阅证规则编号 -->
|
|
|
借阅证规则编号:<%=rs.getString("ID")%>
|
|
|
</button><br><br>
|
|
|
<%
|
|
|
} else {
|
|
|
%>
|
|
|
<!-- 创建一个蓝色按钮,当鼠标悬停或点击时弹出提示框,提示框显示在右侧 -->
|
|
|
<button type="button" class="btn btn-lg btn-primary"
|
|
|
title="可借阅数量:<%=rs.getString("BORROW_NUM") %>"
|
|
|
data-html="true"
|
|
|
data-container="body"
|
|
|
data-trigger="focus"
|
|
|
data-toggle="popover"
|
|
|
data-placement="right"
|
|
|
data-content="可借阅天数:<%=rs.getString("LIMIT_DAY") %><br>可借阅图书馆:<%=rs.getString("BORROW_LIBRARY") %><br>过期扣费/天:<%=rs.getString("OVERTIME_FEE") %>"
|
|
|
style="width:40%;height:100%;font-size:17px;margin-top:4%;">
|
|
|
<!-- 显示借阅证规则编号 -->
|
|
|
借阅证规则编号:<%=rs.getString("ID")%>
|
|
|
</button><br><br>
|
|
|
<%
|
|
|
}
|
|
|
}
|
|
|
%>
|
|
|
</div>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ 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>
|
|
|
<!-- 设置字符编码为 UTF-8 -->
|
|
|
<meta charset="utf-8">
|
|
|
<!-- 设置页面在 IE 浏览器中的渲染模式 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为 1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,此处为空 -->
|
|
|
<title></title>
|
|
|
|
|
|
<!-- 引入 Bootstrap 的 CSS 文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入 jQuery 库,因为 Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入 Bootstrap 的 JavaScript 文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
|
|
|
<!-- 引入自定义的消息样式文件 -->
|
|
|
<link rel="stylesheet" id="templatecss" type="text/css" href="../public/css/message.css">
|
|
|
</head>
|
|
|
<body id="home">
|
|
|
<script>
|
|
|
// 此部分代码被注释掉了,原本功能是获取当前日期时间并显示在弹窗中
|
|
|
// 同时尝试将日期时间赋值给一个 id 为 date_info 的输入框
|
|
|
//$(document).ready(function () {
|
|
|
// var date = new Date(+new Date()+8*3600*1000).toISOString().replace(/T/g,' ').replace(/\.[\d]{3}Z/,'');
|
|
|
// alert(date);//2017-01-22 11:08:46
|
|
|
// $('#date_info').val(today);
|
|
|
//})
|
|
|
</script>
|
|
|
<!-- 外层 div,可能用于自定义样式(根据 message.css 文件) -->
|
|
|
<div class="rain">
|
|
|
<!-- 内层 div,可能用于定义边框样式等 -->
|
|
|
<div class="border start">
|
|
|
<!-- 创建一个表单,表单数据将以 POST 方式提交到 14messageSub.jsp -->
|
|
|
<form action="14messageSub.jsp" method="post">
|
|
|
<!-- 留言板标签,设置左边距 -->
|
|
|
<label for="mes" style="margin-left:36%;">留言板</label>
|
|
|
<!-- 文本区域,用于用户输入留言内容 -->
|
|
|
<textarea id="mes" name="msg" placeholder="请输入您的留言" style="height:50%;width:90%"></textarea>
|
|
|
<!-- 以下三行是被注释掉的代码,原本用于添加日期输入框 -->
|
|
|
<!-- <label for="date">日期</label>-->
|
|
|
<!-- <input id="date" type="text" name="time" placeholder="请输入时间" style="width:90%"/><br> -->
|
|
|
<!-- <input type="datetime_local" id="date_info" placeholder="请输入时间"/> -->
|
|
|
<br><br>
|
|
|
<!-- 按钮区域,居中对齐 -->
|
|
|
<div align="center">
|
|
|
<!-- 提交按钮,点击后将表单数据提交到指定的 action 页面 -->
|
|
|
<button type="submit" class="btn btn-warning" style="margin-left:0">提交</button>   
|
|
|
<!-- 重置按钮,点击后清空表单中的所有输入内容 -->
|
|
|
<button type="reset" class="btn btn-danger" style="margin-right:0">重置</button>   
|
|
|
<!-- 查看留言按钮,点击后跳转到 15checkMessage.jsp 页面 -->
|
|
|
<button type="reset" class="btn btn-info" style="margin-right:0" onClick="location.href='15checkMessage.jsp'">查看留言</button>
|
|
|
</div>
|
|
|
</form>
|
|
|
</div>
|
|
|
</div>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ page import="java.sql.*" %>
|
|
|
<%@ page import="java.util.*" %>
|
|
|
<%@ page import="javabean.DateTime"%>
|
|
|
<%@ 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 charset="utf-8">
|
|
|
<!-- 兼容 IE 浏览器 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 响应式布局设置 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,此处为空 -->
|
|
|
<title></title>
|
|
|
|
|
|
<!-- 引入 Bootstrap 样式 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入 jQuery 库,因为 Bootstrap 的 JavaScript 插件依赖于它 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入 Bootstrap JavaScript 文件 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
|
|
|
<!-- 引入自定义的消息样式文件 -->
|
|
|
<link rel="stylesheet" id="templatecss" type="text/css"
|
|
|
href="../public/css/message.css">
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 使用 JSP 的 useBean 标签创建一个名为 msg 的 JavaBean 实例,作用域为会话级别,类名为 javabean.JDBCBean -->
|
|
|
<jsp:useBean id="msg" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
<%
|
|
|
// 创建 DateTime 类的实例,用于获取日期时间
|
|
|
DateTime date = new DateTime();
|
|
|
// 获取当前日期时间
|
|
|
String time = date.show();
|
|
|
|
|
|
// 从请求中获取用户输入的留言内容
|
|
|
String mes = request.getParameter("msg");
|
|
|
|
|
|
try {
|
|
|
// 从会话中获取读者的借阅证编号,并转换为字符串
|
|
|
String card = session.getAttribute("reader").toString();
|
|
|
// 构建 SQL 插入语句,将读者的借阅证编号、留言内容和留言时间插入到 message 表中
|
|
|
String sql = "insert into message(card_id,detail,public_date)values('" + card + "','" + mes + "','" + time + "');";
|
|
|
|
|
|
// 检查借阅证编号和留言内容是否不为空,且留言内容不是仅包含空白字符
|
|
|
if (card != null && mes != null && !mes.trim().equals("")) {
|
|
|
// 调用 JDBCBean 实例的 executeUpdate 方法执行 SQL 插入语句,并获取受影响的行数
|
|
|
int i = msg.executeUpdate(sql);
|
|
|
|
|
|
// 如果受影响的行数为 1,说明插入成功
|
|
|
if (i == 1) {
|
|
|
%>
|
|
|
<script>
|
|
|
// 弹出提示框,告知用户留言成功
|
|
|
alert('留言成功!');
|
|
|
// 页面跳转到查看留言的页面
|
|
|
window.location.href = "15checkMessage.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
} else {
|
|
|
%>
|
|
|
<script>
|
|
|
// 弹出提示框,告知用户留言未成功
|
|
|
alert('留言未成功!');
|
|
|
// 页面跳转到留言输入页面
|
|
|
window.location.href = "13message.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
} else {
|
|
|
%>
|
|
|
<script>
|
|
|
// 弹出提示框,告知用户留言未成功且留言不能为空
|
|
|
alert('留言未成功!留言不能为空!');
|
|
|
// 页面跳转到留言输入页面
|
|
|
window.location.href = "13message.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
<%
|
|
|
// 捕获异常,当出现异常时执行以下操作
|
|
|
} catch (Exception e) {
|
|
|
%>
|
|
|
<script>
|
|
|
// 弹出提示框,告知用户留言未成功并提示先登录
|
|
|
alert('留言未成功!请先登录!');
|
|
|
// 页面跳转到借阅图书页面
|
|
|
window.location.href = "06borrowBooks.jsp";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ page import="java.sql.*" %>
|
|
|
<%@ page import="java.util.*" %>
|
|
|
<%@ page import="javabean.DateTime"%>
|
|
|
<%@ 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>
|
|
|
<!-- 设置页面字符编码为 UTF-8 -->
|
|
|
<meta charset="utf-8">
|
|
|
<!-- 设置页面在 IE 浏览器中的渲染模式 -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为 1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<!-- 页面标题,此处为空 -->
|
|
|
<title></title>
|
|
|
|
|
|
<!-- 引入 Bootstrap 的 CSS 文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入 jQuery 库,因为 Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入 Bootstrap 的 JavaScript 文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
|
|
|
<!-- 引入自定义的消息样式文件 -->
|
|
|
<link rel="stylesheet" id="templatecss" type="text/css" href="../public/css/message.css">
|
|
|
<style type="text/css">
|
|
|
/* 设置具有 text-dark 类的元素的文字颜色为黑色,字体为幼圆 */
|
|
|
.text-dark{
|
|
|
color:black;
|
|
|
font-family:YouYuan;
|
|
|
}
|
|
|
/* 设置页面主体的背景颜色为白色,字体大小为 16px */
|
|
|
body{
|
|
|
background-color:#fff;
|
|
|
font-size:16px;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- 使用 JSP 的 useBean 标签创建一个名为 msg 的 JavaBean 实例,作用域为会话级别,类名为 javabean.JDBCBean -->
|
|
|
<jsp:useBean id="msg" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
<!-- 创建一个居中对齐的 div,显示留言板标题 -->
|
|
|
<div align="center"><h3 style="color:#F08080;">☆★留言板★☆</h3></div>
|
|
|
<%
|
|
|
// 定义 SQL 查询语句,从 message 表中查询 CARD_ID、DETAIL 和 PUBLIC_DATE 字段,并按 PUBLIC_DATE 降序排列
|
|
|
String sql = "select CARD_ID,DETAIL,PUBLIC_DATE from message order by PUBLIC_DATE desc";
|
|
|
// 调用 JavaBean 的 executeQuery 方法执行 SQL 查询,并将结果存储在 ResultSet 对象中
|
|
|
ResultSet rs = msg.executeQuery(sql);
|
|
|
// 遍历 ResultSet 对象,处理每一条查询结果
|
|
|
while (rs.next()) {
|
|
|
%>
|
|
|
<!-- 创建一个 Bootstrap 的面板组件,宽度为页面宽度的 60%,左边距为 20% -->
|
|
|
<div class="panel panel-default" style="width:60%;height:80%; margin-left:20%;">
|
|
|
<!-- 面板主体内容,居中对齐 -->
|
|
|
<div class="panel-body" align="center">
|
|
|
<!-- 显示留言者的借阅证编号,使用 bg-info 类设置背景颜色,text-dark 类设置文字样式 -->
|
|
|
<p class="bg-info text-dark"><%=rs.getString("CARD_ID")%></p>
|
|
|
<!-- 创建一个 div,设置文字换行 -->
|
|
|
<div style="word-wrap:break-word;">
|
|
|
<!-- 显示留言内容,使用 bg-warning 类设置背景颜色,text-dark 类设置文字样式 -->
|
|
|
<p class="bg-warning text-dark"><%=rs.getString("DETAIL")%></p>
|
|
|
</div>
|
|
|
<!-- 显示留言的发布日期,使用 bg-danger 类设置背景颜色,text-dark 类设置文字样式 -->
|
|
|
<p class="bg-danger text-dark"><%=rs.getString("PUBLIC_DATE")%></p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 插入一条水平线,用于分隔不同的留言 -->
|
|
|
<hr>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
</body>
|
|
|
</html>
|
|
|
<%@ page import="java.sql.*"%>
|
|
|
<%@ 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>
|
|
|
<!-- 设置字符编码为 UTF-8 -->
|
|
|
<meta charset="UTF-8" />
|
|
|
<!-- 让页面在 IE 浏览器中以最新的渲染模式显示,支持 Chrome Frame -->
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
|
<!-- 设置页面在移动设备上的视图,宽度为设备宽度,初始缩放比例为 1 -->
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<!-- 页面标题 -->
|
|
|
<title>Nifty Modal Window Effects</title>
|
|
|
<!-- 页面描述 -->
|
|
|
<meta name="description"
|
|
|
content="Nifty Modal Window Effects with CSS Transitions and Animations" />
|
|
|
<!-- 页面关键词 -->
|
|
|
<meta name="keywords"
|
|
|
content="modal, window, overlay, modern, box, css transition, css animation, effect, 3d, perspective" />
|
|
|
<!-- 页面作者 -->
|
|
|
<meta name="author" content="Codrops" />
|
|
|
|
|
|
<!-- 引入 Bootstrap 的 CSS 文件,用于页面样式布局 -->
|
|
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
|
|
<!-- 引入 jQuery 库,因为 Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边 -->
|
|
|
<script src="../js/jquery.min.js"></script>
|
|
|
<!-- 引入 Bootstrap 的 JavaScript 文件,用于实现交互效果 -->
|
|
|
<script src="../js/bootstrap.min.js"></script>
|
|
|
|
|
|
<!-- 引入自定义的默认样式文件 -->
|
|
|
<link rel="stylesheet" type="text/css" href="../public/css/default.css" />
|
|
|
<!-- 引入自定义的组件样式文件 -->
|
|
|
<link rel="stylesheet" type="text/css"
|
|
|
href="../public/css/component.css" />
|
|
|
<!-- 引入现代特性检测库,用于检测浏览器是否支持某些 CSS3 特性 -->
|
|
|
<script src="../public/js/modernizr.custom.js"></script>
|
|
|
</head>
|
|
|
<body>
|
|
|
<%
|
|
|
// 检查会话中是否存在 "reader" 属性,如果不存在则表示用户未登录
|
|
|
if (session.getAttribute("reader") == null) {
|
|
|
%>
|
|
|
<script>
|
|
|
// 如果用户未登录,将页面重定向到登录页面
|
|
|
location.href = "../loginReader.html";
|
|
|
</script>
|
|
|
<%
|
|
|
}
|
|
|
%>
|
|
|
<!-- 使用 JSP 的 useBean 标签创建一个名为 check 的 JavaBean 实例,作用域为会话级别,类名为 javabean.JDBCBean -->
|
|
|
<jsp:useBean id="check" scope="session" class="javabean.JDBCBean"></jsp:useBean>
|
|
|
<!-- 模态框,用于修改密码 -->
|
|
|
<div class="md-modal md-effect-13" id="modal-13">
|
|
|
<div class="md-content">
|
|
|
<!-- 模态框标题 -->
|
|
|
<h3>修改密码</h3>
|
|
|
<!-- 表单,用于输入新密码并提交到 11updatePswSus.jsp 页面 -->
|
|
|
<form action="11updatePswSus.jsp" method="post"
|
|
|
class="form-horizontal">
|
|
|
<div class="form-group" align="center">
|
|
|
<br>
|
|
|
<!-- 新密码标签 -->
|
|
|
<label for="psw1" class="col-sm-2 control-label">新密码</label>
|
|
|
<div class="col-sm-10" align="center">
|
|
|
<!-- 新密码输入框 -->
|
|
|
<input type="password" class="form-control" name="psw1" id="password1" placeholder="请输入新密码" style="width:70%;"/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<br>
|
|
|
<div class="form-group" align="center">
|
|
|
<!-- 再次输入新密码标签 -->
|
|
|
<label for="psw2" class="col-sm-2 control-label">新密码</label>
|
|
|
<div class="col-sm-10">
|
|
|
<!-- 再次输入新密码输入框 -->
|
|
|
<input type="password" class="form-control" name="psw2" id="password2" placeholder="请再次输入密码进行确认" style="width:70%;"/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div align="center">
|
|
|
<!-- 提交按钮 -->
|
|
|
<input type="submit" class="btn btn-primary" value="确认">
|
|
|
</div>
|
|
|
<br>
|
|
|
</form>
|
|
|
<!-- 取消按钮,用于关闭模态框 -->
|
|
|
<button class="md-close btn-primary">取消</button>
|
|
|
<br>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="container">
|
|
|
<!-- 页面头部 -->
|
|
|
<header style="backgorund-color:lightblue;height:20%;font-align:center;width:100%;font-family:YouYuan;">
|
|
|
<!-- 页面标题 -->
|
|
|
<h1>个人信息
|
|
|
<!-- 图标和提示信息 -->
|
|
|
<span class="glyphicon glyphicon-bookmark" aria-hidden="true" style="font-size:17px;"> Success is waking up in the morning,so excited about what you have to do.</span>
|
|
|
</h1>
|
|
|
</header>
|
|
|
|
|
|
<div class="main clearfix" style="font-size:10px;margin-top:5%;font-family:YouYuan;">
|
|
|
<div class="column">
|
|
|
<%
|
|
|
try {
|
|
|
// 从会话中获取当前登录读者的借阅证编号
|
|
|
String cardId = session.getAttribute("reader").toString();
|
|
|
// 构建 SQL 查询语句,从 borrow_card 表中查询当前读者的信息
|
|
|
String sql = "select*from borrow_card where ID = '" + cardId + "';";
|
|
|
// 调用 JavaBean 的 executeQuery 方法执行 SQL 查询,并将结果存储在 ResultSet 对象中
|
|
|
ResultSet rs = check.executeQuery(sql);
|
|
|
// 遍历查询结果
|
|
|
while (rs.next()) {
|
|
|
// 获取借阅证编号
|
|
|
int id = rs.getInt(1);
|
|
|
%>
|
|
|
<!-- 显示借阅证编号 -->
|
|
|
<p><span class="glyphicon glyphicon-tags"> 借阅证编号:<%=rs.getString("ID")%></span></p><br>
|
|
|
<!-- 显示借阅证姓名 -->
|
|
|
<p><span class="glyphicon glyphicon-user"> 借阅证姓名:<%=rs.getString("READER")%></span></p><br>
|
|
|
<!-- 显示规则编号 -->
|
|
|
<p><span class="glyphicon glyphicon-tag"> 规则编号:<%=rs.getString("RULE_ID")%></span></p><br>
|
|
|
<!-- 显示借阅证状态 -->
|
|
|
<p><span class="glyphicon glyphicon-star-empty"> 状态:
|
|
|
<%
|
|
|
// 根据 STATUS 字段的值判断借阅证状态
|
|
|
if (rs.getString("STATUS").equals("1")) {
|
|
|
out.println("可用");
|
|
|
} else {
|
|
|
out.println("挂失");
|
|
|
}
|
|
|
%>
|
|
|
</span></p>
|
|
|
<%
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
// 异常处理,可根据实际需求添加日志记录等操作
|
|
|
}
|
|
|
%>
|
|
|
</div>
|
|
|
<div class="column" align="center" style="font-size:15px">
|
|
|
<!-- 修改密码按钮,点击后弹出模态框 -->
|
|
|
<button class="md-trigger" data-modal="modal-13" style="margin-top:20%;">修改密码</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 模态框遮罩层 -->
|
|
|
<div class="md-overlay"></div>
|
|
|
|
|
|
<!-- 引入 classie.js 库,用于操作 DOM 元素的类名 -->
|
|
|
<script src="../public/js/classie.js"></script>
|
|
|
<!-- 引入模态框效果的 JavaScript 文件 -->
|
|
|
<script src="../public/js/modalEffects.js"></script>
|
|
|
|
|
|
<!-- 为了实现模糊效果引入的脚本 -->
|
|
|
<script>
|
|
|
// 这对于 IE 浏览器很重要
|
|
|
var polyfilter_scriptpath = '/js/';
|
|
|
</script>
|
|
|
<script src="../public/js/cssParser.js"></script>
|
|
|
<script src="../public/js/css-filters-polyfill.js"></script>
|
|
|
</body>
|
|
|
</html>
|
|
|
package javabean;
|
|
|
|
|
|
// 导入 java.sql 包中的相关类,用于与数据库进行交互
|
|
|
import java.sql.Connection;
|
|
|
import java.sql.DriverManager;
|
|
|
import java.sql.PreparedStatement;
|
|
|
import java.sql.ResultSet;
|
|
|
import java.sql.SQLException;
|
|
|
|
|
|
/**
|
|
|
* 该类提供了与数据库交互的基础方法,包括获取数据库连接、执行查询、执行更新以及释放资源等操作。
|
|
|
*/
|
|
|
public class Base {
|
|
|
// 从 DBConstants 类中获取数据库驱动信息,并将其设置为常量,后续不可修改
|
|
|
private static final String driver = DBConstants.driver;
|
|
|
// 从 DBConstants 类中获取数据库连接的 URL 信息,并将其设置为常量,后续不可修改
|
|
|
private static final String url = DBConstants.url;
|
|
|
// 从 DBConstants 类中获取数据库用户名信息,并将其设置为常量,后续不可修改
|
|
|
private static final String username = DBConstants.username;
|
|
|
// 从 DBConstants 类中获取数据库密码信息,并将其设置为常量,后续不可修改
|
|
|
private static final String password = DBConstants.password;
|
|
|
|
|
|
/**
|
|
|
* 获取数据库连接
|
|
|
*
|
|
|
* @return 返回一个数据库连接对象,如果连接失败则返回 null
|
|
|
* @throws ClassNotFoundException 如果找不到数据库驱动类,抛出该异常
|
|
|
*/
|
|
|
public static Connection getConnection() throws ClassNotFoundException {
|
|
|
// 初始化数据库连接对象为 null
|
|
|
Connection connection = null;
|
|
|
try {
|
|
|
// 加载数据库驱动类
|
|
|
Class.forName(driver);
|
|
|
// 通过 DriverManager 获取数据库连接
|
|
|
connection = (Connection) DriverManager.getConnection(url, username, password);
|
|
|
} catch (SQLException e) {
|
|
|
// 若发生 SQL 异常,打印异常堆栈信息
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
// 返回数据库连接对象
|
|
|
return connection;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 公共查询方法,用于执行 SQL 查询语句
|
|
|
*
|
|
|
* @param connection 数据库连接对象,用于与数据库建立连接
|
|
|
* @param preparedStatement 预编译的 SQL 语句对象,用于执行带参数的 SQL 语句
|
|
|
* @param resultSet 结果集对象,用于存储查询结果
|
|
|
* @param sql 要执行的 SQL 查询语句
|
|
|
* @param params SQL 语句中的参数数组
|
|
|
* @return 返回包含查询结果的结果集对象
|
|
|
* @throws SQLException 如果执行 SQL 语句时发生错误,抛出该异常
|
|
|
*/
|
|
|
public static ResultSet executequery(Connection connection, PreparedStatement preparedStatement,
|
|
|
ResultSet resultSet, String sql, Object[] params) throws SQLException {
|
|
|
// 如果预编译的 SQL 语句对象为空,则创建一个新的预编译对象
|
|
|
if (preparedStatement == null) {
|
|
|
preparedStatement = (PreparedStatement) connection.prepareStatement(sql);
|
|
|
}
|
|
|
// 遍历参数数组,将参数设置到预编译的 SQL 语句中
|
|
|
for (int i = 0; params != null && i < params.length; i++) {
|
|
|
preparedStatement.setObject(i + 1, params[i]);
|
|
|
}
|
|
|
// 执行查询语句,并将结果存储在结果集对象中
|
|
|
resultSet = preparedStatement.executeQuery();
|
|
|
// 返回结果集对象
|
|
|
return resultSet;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 公共修改方法,用于执行 SQL 更新、插入、删除等语句
|
|
|
*
|
|
|
* @param connection 数据库连接对象,用于与数据库建立连接
|
|
|
* @param preparedStatement 预编译的 SQL 语句对象,用于执行带参数的 SQL 语句
|
|
|
* @param sql 要执行的 SQL 修改语句
|
|
|
* @param params SQL 语句中的参数数组
|
|
|
* @return 返回受影响的行数
|
|
|
* @throws SQLException 如果执行 SQL 语句时发生错误,抛出该异常
|
|
|
*/
|
|
|
public static int executeUpdate(Connection connection, PreparedStatement preparedStatement, String sql,
|
|
|
Object[] params) throws SQLException {
|
|
|
// 如果预编译的 SQL 语句对象为空,则创建一个新的预编译对象
|
|
|
if (preparedStatement == null) {
|
|
|
preparedStatement = (PreparedStatement) connection.prepareStatement(sql);
|
|
|
}
|
|
|
// 遍历参数数组,将参数设置到预编译的 SQL 语句中
|
|
|
for (int i = 0; params != null && i < params.length; i++) {
|
|
|
preparedStatement.setObject(i + 1, params[i]);
|
|
|
}
|
|
|
// 执行更新语句,并返回受影响的行数
|
|
|
int updateRows = preparedStatement.executeUpdate();
|
|
|
// 返回受影响的行数
|
|
|
return updateRows;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 释放数据库资源,包括结果集、预编译语句和数据库连接
|
|
|
*
|
|
|
* @param connection 数据库连接对象
|
|
|
* @param preparedStatement 预编译的 SQL 语句对象
|
|
|
* @param resultSet 结果集对象
|
|
|
* @return 如果所有资源都成功释放,返回 true;否则返回 false
|
|
|
* @throws SQLException 如果关闭资源时发生错误,抛出该异常
|
|
|
*/
|
|
|
public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet)
|
|
|
throws SQLException {
|
|
|
// 初始化标志位为 true,表示资源释放成功
|
|
|
boolean flag = true;
|
|
|
// 如果结果集对象不为空,则尝试关闭结果集
|
|
|
if (resultSet != null) {
|
|
|
try {
|
|
|
resultSet.close();
|
|
|
// 关闭后将结果集对象置为 null,便于垃圾回收
|
|
|
resultSet = null;
|
|
|
} catch (SQLException e) {
|
|
|
// 若关闭结果集时发生异常,打印异常堆栈信息,并将标志位设为 false
|
|
|
e.printStackTrace();
|
|
|
flag = false;
|
|
|
}
|
|
|
}
|
|
|
// 如果预编译语句对象不为空,则尝试关闭预编译语句
|
|
|
if (preparedStatement != null) {
|
|
|
try {
|
|
|
preparedStatement.close();
|
|
|
// 关闭后将预编译语句对象置为 null,便于垃圾回收
|
|
|
preparedStatement = null;
|
|
|
} catch (SQLException e) {
|
|
|
// 若关闭预编译语句时发生异常,打印异常堆栈信息,并将标志位设为 false
|
|
|
e.printStackTrace();
|
|
|
flag = false;
|
|
|
}
|
|
|
}
|
|
|
// 如果数据库连接对象不为空,则尝试关闭数据库连接
|
|
|
if (connection != null) {
|
|
|
try {
|
|
|
connection.close();
|
|
|
// 关闭后将数据库连接对象置为 null,便于垃圾回收
|
|
|
connection = null;
|
|
|
} catch (SQLException e) {
|
|
|
// 若关闭数据库连接时发生异常,打印异常堆栈信息,并将标志位设为 false
|
|
|
e.printStackTrace();
|
|
|
flag = false;
|
|
|
}
|
|
|
}
|
|
|
// 返回标志位
|
|
|
return flag;
|
|
|
}
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
import java.sql.Connection;
|
|
|
import java.sql.PreparedStatement;
|
|
|
import java.sql.ResultSet;
|
|
|
import java.sql.SQLException;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.TreeMap;
|
|
|
|
|
|
/**
|
|
|
* Common 类提供了一些通用的数据库操作方法,例如获取指定表的行数和获取图书馆信息的映射。
|
|
|
*/
|
|
|
public class Common {
|
|
|
|
|
|
/**
|
|
|
* 获取指定表的行总数。
|
|
|
*
|
|
|
* @param table 要查询的表名
|
|
|
* @return 表中的行数,如果表名为空或者查询过程中出现异常则返回 0
|
|
|
* @throws SQLException 如果在执行 SQL 语句时发生数据库访问错误
|
|
|
* @throws ClassNotFoundException 如果无法找到数据库驱动类
|
|
|
*/
|
|
|
public static int getCount(String table) throws SQLException, ClassNotFoundException {
|
|
|
// 检查传入的表名是否为空或 null,如果是则直接返回 0
|
|
|
if (table == null || table.equals("")) {
|
|
|
return 0;
|
|
|
}
|
|
|
// 声明数据库连接对象
|
|
|
Connection connection = null;
|
|
|
// 声明预编译 SQL 语句对象
|
|
|
PreparedStatement pstmt = null;
|
|
|
// 声明结果集对象
|
|
|
ResultSet resultSet = null;
|
|
|
// 通过 Base 类的 getConnection 方法获取数据库连接
|
|
|
connection = Base.getConnection();
|
|
|
try {
|
|
|
// 准备 SQL 查询语句,用于统计指定表的行数
|
|
|
pstmt = connection.prepareStatement("select count(*) as count from " + table);
|
|
|
// 执行查询操作,将结果存储在结果集对象中
|
|
|
resultSet = pstmt.executeQuery();
|
|
|
// 将结果集指针移动到第一行
|
|
|
resultSet.next();
|
|
|
// 从结果集中获取名为 "count" 的列的值,并返回该值
|
|
|
return resultSet.getInt("count");
|
|
|
} catch (Exception e) {
|
|
|
// 如果查询过程中出现异常,返回 0
|
|
|
return 0;
|
|
|
} finally {
|
|
|
// 无论查询是否成功,都调用 Base 类的 closeResource 方法关闭数据库连接、预编译语句和结果集
|
|
|
Base.closeResource(connection, pstmt, resultSet);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取图书馆信息的映射,键为图书馆的 ID,值为图书馆的名称。
|
|
|
*
|
|
|
* @return 包含图书馆信息的 TreeMap,如果出现异常则返回 null
|
|
|
* @throws SQLException 如果在执行 SQL 语句时发生数据库访问错误
|
|
|
*/
|
|
|
public static TreeMap<String, String> getLibraryMap() throws SQLException {
|
|
|
// 声明数据库连接对象
|
|
|
Connection connection = null;
|
|
|
// 声明用于查询图书馆信息的预编译 SQL 语句对象
|
|
|
PreparedStatement libraryPstmt = null;
|
|
|
// 声明用于存储图书馆信息查询结果的结果集对象
|
|
|
ResultSet librarySet = null;
|
|
|
// 定义查询图书馆信息的 SQL 语句
|
|
|
String librarySql = "select id,name from library";
|
|
|
|
|
|
// 创建一个 TreeMap 用于存储图书馆信息,TreeMap 会根据键的自然顺序进行排序
|
|
|
TreeMap<String, String> map = new TreeMap<String, String>();
|
|
|
// 获取图书馆信息
|
|
|
try {
|
|
|
// 通过 Base 类的 getConnection 方法获取数据库连接
|
|
|
connection = (Connection) Base.getConnection();
|
|
|
// 准备查询图书馆信息的 SQL 语句
|
|
|
libraryPstmt = connection.prepareStatement(librarySql);
|
|
|
// 执行查询操作,将结果存储在结果集对象中
|
|
|
librarySet = libraryPstmt.executeQuery();
|
|
|
// 遍历结果集
|
|
|
while (librarySet.next()) {
|
|
|
// 将图书馆的 ID 作为键,图书馆的名称作为值,存入 TreeMap 中
|
|
|
map.put(librarySet.getString("id"), librarySet.getString("name"));
|
|
|
}
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
// 如果找不到数据库驱动类,返回 null
|
|
|
return null;
|
|
|
} catch (SQLException e) {
|
|
|
// 如果执行 SQL 语句时发生异常,返回 null
|
|
|
return null;
|
|
|
} finally {
|
|
|
// 无论查询是否成功,都调用 Base 类的 closeResource 方法关闭数据库连接、预编译语句和结果集
|
|
|
Base.closeResource(connection, libraryPstmt, librarySet);
|
|
|
}
|
|
|
// 返回存储图书馆信息的 TreeMap
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 主方法,用于测试 getLibraryMap 方法。
|
|
|
*
|
|
|
* @param args 命令行参数
|
|
|
* @throws SQLException 如果在执行 SQL 语句时发生数据库访问错误
|
|
|
*/
|
|
|
public static void main(String[] args) throws SQLException {
|
|
|
// 调用 getLibraryMap 方法并打印结果
|
|
|
System.out.println(Common.getLibraryMap());
|
|
|
}
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
import java.text.ParseException;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.Date;
|
|
|
|
|
|
/**
|
|
|
* CompareDate 类用于比较两个日期字符串所表示的日期之间的天数差。
|
|
|
*/
|
|
|
public class CompareDate {
|
|
|
/**
|
|
|
* 该方法用于计算两个日期字符串所表示的日期之间相差的天数。
|
|
|
*
|
|
|
* @param Str1 第一个日期字符串,格式必须为 "yyyy-MM-dd HH:mm:ss"
|
|
|
* @param Str2 第二个日期字符串,格式必须为 "yyyy-MM-dd HH:mm:ss"
|
|
|
* @return 两个日期之间相差的天数,如果解析日期字符串时发生异常则返回 0
|
|
|
*/
|
|
|
public static long show(String Str1, String Str2) {
|
|
|
// 用于存储两个日期之间的毫秒差值
|
|
|
long between = 0;
|
|
|
// 创建一个 SimpleDateFormat 对象,指定日期字符串的格式为 "yyyy-MM-dd HH:mm:ss"
|
|
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
try {
|
|
|
// 将第一个日期字符串解析为 Date 对象
|
|
|
Date date1 = format.parse(Str1);
|
|
|
// 将第二个日期字符串解析为 Date 对象
|
|
|
Date date2 = format.parse(Str2);
|
|
|
// 计算两个日期对象之间的毫秒差值
|
|
|
between = (date2.getTime() - date1.getTime());
|
|
|
// 打印第一个日期对象,方便调试查看
|
|
|
System.out.println(date1);
|
|
|
// 打印第二个日期对象,方便调试查看
|
|
|
System.out.println(date2);
|
|
|
} catch (ParseException e) {
|
|
|
// 如果在解析日期字符串时发生异常,打印异常堆栈信息
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
// 将毫秒差值转换为天数,一天有 24 小时,每小时 60 分钟,每分钟 60 秒,每秒 1000 毫秒
|
|
|
long days = between / (24 * 60 * 60 * 1000);
|
|
|
// 返回计算得到的天数差值
|
|
|
return days;
|
|
|
}
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.Calendar;
|
|
|
import java.util.Date;
|
|
|
|
|
|
/**
|
|
|
* DateTime 类提供了一系列用于日期和时间处理的静态方法,
|
|
|
* 可以获取当前日期时间、计算指定天数偏移后的日期时间等。
|
|
|
*/
|
|
|
public class DateTime {
|
|
|
|
|
|
/**
|
|
|
* 获取当前日期和时间,格式为 "yyyy-MM-dd HH:mm:ss"。
|
|
|
*
|
|
|
* @return 格式化后的当前日期和时间字符串
|
|
|
*/
|
|
|
public static String show() {
|
|
|
// 创建一个 SimpleDateFormat 对象,指定日期时间的格式为 "yyyy-MM-dd HH:mm:ss"
|
|
|
SimpleDateFormat myFmt2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
// 获取当前日期和时间
|
|
|
Date now = new Date();
|
|
|
// 使用指定格式将当前日期和时间转换为字符串并返回
|
|
|
return myFmt2.format(now);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取指定天数偏移后的日期和时间,格式为 "yyyy-MM-dd HH:mm:ss"。
|
|
|
*
|
|
|
* @param n 要偏移的天数,正数表示未来的日期,负数表示过去的日期
|
|
|
* @return 格式化后的偏移日期和时间字符串
|
|
|
*/
|
|
|
public static String show(int n) {
|
|
|
// 获取当前日期和时间
|
|
|
Date d = new Date();
|
|
|
// 创建一个 SimpleDateFormat 对象,指定日期时间的格式为 "yyyy-MM-dd HH:mm:ss"
|
|
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
// 将当前日期和时间按照指定格式转换为字符串
|
|
|
String currdate = format.format(d);
|
|
|
// 获取一个 Calendar 实例,用于日期计算
|
|
|
Calendar ca = Calendar.getInstance();
|
|
|
// 在当前日期的基础上增加或减少指定的天数
|
|
|
ca.add(Calendar.DATE, n);
|
|
|
// 获取计算后的日期
|
|
|
d = ca.getTime();
|
|
|
// 将计算后的日期按照指定格式转换为字符串
|
|
|
String enddate = format.format(d);
|
|
|
// 返回计算后的日期和时间字符串
|
|
|
return enddate;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取指定天数偏移后的日期,只包含年、月、日,格式为 "yyyy-MM-dd"。
|
|
|
*
|
|
|
* @param n 要偏移的天数,正数表示未来的日期,负数表示过去的日期
|
|
|
* @return 格式化后的偏移日期字符串
|
|
|
*/
|
|
|
public static String showDate(int n) {
|
|
|
// 获取当前日期和时间
|
|
|
Date d = new Date();
|
|
|
// 创建一个 SimpleDateFormat 对象,指定日期的格式为 "yyyy-MM-dd"
|
|
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
// 将当前日期按照指定格式转换为字符串
|
|
|
String currdate = format.format(d);
|
|
|
// 获取一个 Calendar 实例,用于日期计算
|
|
|
Calendar ca = Calendar.getInstance();
|
|
|
// 在当前日期的基础上增加或减少指定的天数
|
|
|
ca.add(Calendar.DATE, n);
|
|
|
// 获取计算后的日期
|
|
|
d = ca.getTime();
|
|
|
// 将计算后的日期按照指定格式转换为字符串
|
|
|
String enddate = format.format(d);
|
|
|
// 返回计算后的日期字符串
|
|
|
return enddate;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取指定天数偏移后的日期,只包含月和日,格式为 "MM-dd"。
|
|
|
*
|
|
|
* @param n 要偏移的天数,正数表示未来的日期,负数表示过去的日期
|
|
|
* @return 格式化后的偏移日期字符串
|
|
|
*/
|
|
|
public static String showMD(int n) {
|
|
|
// 获取当前日期和时间
|
|
|
Date d = new Date();
|
|
|
// 创建一个 SimpleDateFormat 对象,指定日期的格式为 "MM-dd"
|
|
|
SimpleDateFormat format = new SimpleDateFormat("MM-dd");
|
|
|
// 将当前日期按照指定格式转换为字符串
|
|
|
String currdate = format.format(d);
|
|
|
// 获取一个 Calendar 实例,用于日期计算
|
|
|
Calendar ca = Calendar.getInstance();
|
|
|
// 在当前日期的基础上增加或减少指定的天数
|
|
|
ca.add(Calendar.DATE, n);
|
|
|
// 获取计算后的日期
|
|
|
d = ca.getTime();
|
|
|
// 将计算后的日期按照指定格式转换为字符串
|
|
|
String enddate = format.format(d);
|
|
|
// 返回计算后的日期字符串
|
|
|
return enddate;
|
|
|
}
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
/**
|
|
|
* DBConstants 类用于存储数据库连接所需的常量信息,
|
|
|
* 这些常量包含了数据库驱动、连接 URL、用户名和密码,
|
|
|
* 方便在项目中统一管理和使用数据库连接相关的配置。
|
|
|
*/
|
|
|
public class DBConstants {
|
|
|
/**
|
|
|
* 数据库驱动类的全限定名。这里使用的是 MySQL 8.x 及以上版本的 JDBC 驱动,
|
|
|
* 如果使用的是 MySQL 5.x 版本,驱动类名应为 "com.mysql.jdbc.Driver"。
|
|
|
*/
|
|
|
public static final String driver = "com.mysql.cj.jdbc.Driver";
|
|
|
|
|
|
/**
|
|
|
* 数据库连接的 URL。该 URL 指定了要连接的数据库的地址、端口、数据库名以及一些连接参数。
|
|
|
* - "jdbc:mysql://":表示使用 JDBC 连接 MySQL 数据库的协议。
|
|
|
* - "localhost:3306":表示数据库服务器的地址为本地主机(localhost),端口号为 3306。
|
|
|
* - "library":表示要连接的数据库名。
|
|
|
* - "&useSSL=false":表示不使用 SSL 加密连接。
|
|
|
* - "serverTimezone=UTC":指定数据库服务器的时区为协调世界时(UTC),避免时间处理上的问题。
|
|
|
* - "useUnicode=true&characterEncoding=UTF-8":表示使用 Unicode 字符集,并将字符编码设置为 UTF-8,
|
|
|
* 确保能够正确处理各种语言的字符。
|
|
|
*/
|
|
|
public static final String url = "jdbc:mysql://localhost:3306/library?&useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8";
|
|
|
|
|
|
/**
|
|
|
* 连接数据库时使用的用户名。这里使用的是 MySQL 的默认超级用户 "root",
|
|
|
* 在实际项目中,建议使用具有适当权限的普通用户来连接数据库,以提高安全性。
|
|
|
*/
|
|
|
public static final String username = "root";
|
|
|
|
|
|
/**
|
|
|
* 连接数据库时使用的密码。这里的密码为 "123456",
|
|
|
* 在实际项目中,应使用更复杂、安全的密码,并妥善保管,避免泄露。
|
|
|
*/
|
|
|
public static final String password = "123456";
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.Calendar;
|
|
|
import java.util.Date;
|
|
|
|
|
|
/**
|
|
|
* EndTime 类提供了一个静态方法,用于计算从当前日期开始经过指定天数后的日期和时间。
|
|
|
*/
|
|
|
public class EndTime {
|
|
|
|
|
|
/**
|
|
|
* 计算从当前日期开始经过指定天数后的日期和时间。
|
|
|
*
|
|
|
* @param n 要增加的天数,可以是正数(表示未来的日期)或负数(表示过去的日期)。
|
|
|
* @return 经过指定天数后的日期和时间,格式为 "yyyy-MM-dd HH:mm:ss"。
|
|
|
*/
|
|
|
public static String show(int n) {
|
|
|
// 获取当前日期和时间
|
|
|
Date d = new Date();
|
|
|
// 创建一个 SimpleDateFormat 对象,用于格式化日期和时间,格式为 "yyyy-MM-dd HH:mm:ss"
|
|
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
// 将当前日期和时间格式化为字符串
|
|
|
String currdate = format.format(d);
|
|
|
// 打印当前日期和时间
|
|
|
System.out.println("现在的日期是:" + currdate);
|
|
|
|
|
|
// 获取一个 Calendar 实例,用于进行日期计算
|
|
|
Calendar ca = Calendar.getInstance();
|
|
|
// 在当前日期的基础上增加指定的天数
|
|
|
ca.add(Calendar.DATE, n);
|
|
|
// 获取增加天数后的日期
|
|
|
d = ca.getTime();
|
|
|
// 将增加天数后的日期格式化为字符串
|
|
|
String enddate = format.format(d);
|
|
|
// 返回增加天数后的日期和时间字符串
|
|
|
return enddate;
|
|
|
}
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
import java.sql.Connection;
|
|
|
import java.sql.DriverManager;
|
|
|
import java.sql.ResultSet;
|
|
|
import java.sql.Statement;
|
|
|
|
|
|
/**
|
|
|
* JDBCBean 类封装了与数据库交互的基本操作,包括建立连接、执行更新、执行查询以及关闭连接等功能。
|
|
|
*/
|
|
|
public class JDBCBean {
|
|
|
// 从 DBConstants 类中获取数据库驱动信息,使用 static final 修饰确保其不可变
|
|
|
private static final String driver = DBConstants.driver;
|
|
|
// 从 DBConstants 类中获取数据库连接的 URL 信息,使用 static final 修饰确保其不可变
|
|
|
private static final String url = DBConstants.url;
|
|
|
// 从 DBConstants 类中获取数据库用户名信息,使用 static final 修饰确保其不可变
|
|
|
private static final String username = DBConstants.username;
|
|
|
// 从 DBConstants 类中获取数据库密码信息,使用 static final 修饰确保其不可变
|
|
|
private static final String password = DBConstants.password;
|
|
|
// 数据库连接对象,用于与数据库建立连接
|
|
|
private Connection conn = null;
|
|
|
// 用于执行 SQL 语句的 Statement 对象
|
|
|
private Statement stmt = null;
|
|
|
|
|
|
/**
|
|
|
* 构造函数,在创建 JDBCBean 对象时自动尝试与数据库建立连接。
|
|
|
*/
|
|
|
public JDBCBean() {
|
|
|
try {
|
|
|
// 加载数据库驱动类
|
|
|
Class.forName(driver);
|
|
|
// 通过 DriverManager 获取数据库连接
|
|
|
conn = DriverManager.getConnection(url, username, password);
|
|
|
// 创建一个 Statement 对象,用于执行 SQL 语句
|
|
|
stmt = conn.createStatement();
|
|
|
// 若连接成功,打印提示信息
|
|
|
System.out.println("同数据库建立连接!");
|
|
|
} catch (Exception ex) {
|
|
|
// 若连接过程中出现异常,打印错误提示信息
|
|
|
System.out.println("无法同数据库建立连接!");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 执行 SQL 更新语句(如 INSERT、UPDATE、DELETE)。
|
|
|
*
|
|
|
* @param s 要执行的 SQL 更新语句
|
|
|
* @return 执行更新操作后受影响的行数,若执行出错则返回 0
|
|
|
*/
|
|
|
public int executeUpdate(String s) {
|
|
|
// 用于存储执行更新操作后受影响的行数
|
|
|
int result = 0;
|
|
|
try {
|
|
|
// 打印要执行的 SQL 语句和 Statement 对象信息,方便调试
|
|
|
System.out.println(s + "------" + stmt + "-----");
|
|
|
// 执行 SQL 更新语句,并将受影响的行数赋值给 result
|
|
|
result = stmt.executeUpdate(s);
|
|
|
} catch (Exception e) {
|
|
|
// 若执行更新操作时出现异常,打印错误提示信息
|
|
|
System.out.println("执行更新错误!");
|
|
|
}
|
|
|
// 返回受影响的行数
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 执行 SQL 查询语句(如 SELECT)。
|
|
|
*
|
|
|
* @param s 要执行的 SQL 查询语句
|
|
|
* @return 包含查询结果的 ResultSet 对象,若执行出错则返回 null
|
|
|
*/
|
|
|
public ResultSet executeQuery(String s) {
|
|
|
// 用于存储查询结果的 ResultSet 对象
|
|
|
ResultSet rs = null;
|
|
|
try {
|
|
|
// 执行 SQL 查询语句,并将结果存储在 rs 中
|
|
|
rs = stmt.executeQuery(s);
|
|
|
} catch (Exception e) {
|
|
|
// 若执行查询操作时出现异常,打印错误提示信息和异常信息
|
|
|
System.out.println("执行查询错误! " + e.getMessage());
|
|
|
}
|
|
|
// 返回包含查询结果的 ResultSet 对象
|
|
|
return rs;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 关闭数据库连接和 Statement 对象,释放资源。
|
|
|
*/
|
|
|
public void close() {
|
|
|
try {
|
|
|
// 关闭 Statement 对象
|
|
|
stmt.close();
|
|
|
// 关闭数据库连接
|
|
|
conn.close();
|
|
|
} catch (Exception e) {
|
|
|
// 若关闭过程中出现异常,不做处理
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
package javabean;
|
|
|
|
|
|
import java.math.BigInteger;
|
|
|
import java.security.MessageDigest;
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.Date;
|
|
|
|
|
|
import net.sf.json.JSONObject;
|
|
|
|
|
|
/**
|
|
|
* Util 类提供了一系列实用工具方法,涵盖字符串处理、日期格式化、JSON 数据生成和 MD5 加密等功能。
|
|
|
*/
|
|
|
public class Util {
|
|
|
|
|
|
/**
|
|
|
* 计算字符串中指定子字符串的出现次数。
|
|
|
* 此方法可用于计算 JSON 字符串中特定对象标识的数量。
|
|
|
*
|
|
|
* @param str 要进行检查的原始字符串
|
|
|
* @param contain 要查找的子字符串
|
|
|
* @return 子字符串在原始字符串中出现的次数
|
|
|
*/
|
|
|
public static int getCountString(String str, String contain) {
|
|
|
// 通过替换子字符串后计算长度差,再除以子字符串长度得到出现次数
|
|
|
int count = (str.length() - str.replace(contain, "").length()) / contain.length();
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 格式化从数据库取出的日期时间字符串,去除可能存在的 ".0" 后缀。
|
|
|
*
|
|
|
* @param dateTime 从数据库取出的日期时间字符串
|
|
|
* @return 去除 ".0" 后缀后的日期时间字符串,如果原字符串无 ".0" 或为空则返回原字符串或 null
|
|
|
*/
|
|
|
public static String getFormatDateTime(String dateTime) {
|
|
|
// 若日期时间字符串不为空且包含 ".0"
|
|
|
if (dateTime != null && dateTime.indexOf(".0") != -1) {
|
|
|
// 截取去除 ".0" 后的部分并返回
|
|
|
return dateTime.substring(0, dateTime.length() - 2);
|
|
|
} else if (dateTime != null) {
|
|
|
// 若不包含 ".0" 且不为空,直接返回原字符串
|
|
|
return dateTime;
|
|
|
}
|
|
|
// 若为空则返回 null
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取当前时间的字符串表示,格式为 "yyyy-MM-dd hh:mm:ss"。
|
|
|
*
|
|
|
* @return 当前时间的格式化字符串
|
|
|
*/
|
|
|
public static String getCurrentTimeString() {
|
|
|
// 获取当前日期对象
|
|
|
Date date = new Date();
|
|
|
// 定义日期时间格式化模式
|
|
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
|
|
// 将日期对象按指定格式转换为字符串并返回
|
|
|
return dateFormat.format(date);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成包含状态码、消息和数据的 JSON 格式字符串响应。
|
|
|
*
|
|
|
* @param code 状态码
|
|
|
* @param msg 消息内容
|
|
|
* @param data 附带的数据,如果为 null 则不包含在 JSON 中
|
|
|
* @return 生成的 JSON 格式字符串
|
|
|
*/
|
|
|
public static String jsonResponse(int code, String msg, String data) {
|
|
|
// 创建一个 JSONObject 对象
|
|
|
JSONObject jsonObject = new JSONObject();
|
|
|
// 向 JSON 对象中添加状态码
|
|
|
jsonObject.put("code", code);
|
|
|
// 向 JSON 对象中添加消息内容
|
|
|
jsonObject.put("msg", msg);
|
|
|
// 若数据不为空,则添加到 JSON 对象中
|
|
|
if (data != null) {
|
|
|
jsonObject.put("data", data);
|
|
|
}
|
|
|
// 将 JSON 对象转换为字符串并返回
|
|
|
return jsonObject.toString();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 对输入的字符串进行 MD5 加密。
|
|
|
*
|
|
|
* @param plainText 待加密的明文字符串
|
|
|
* @return 加密后的 32 位 MD5 字符串
|
|
|
*/
|
|
|
public static String stringToMD5(String plainText) {
|
|
|
byte[] secretBytes = null;
|
|
|
try {
|
|
|
// 获取 MD5 算法的 MessageDigest 实例
|
|
|
MessageDigest md = MessageDigest.getInstance("md5");
|
|
|
// 对输入字符串的字节数组进行加密处理
|
|
|
secretBytes = md.digest(plainText.getBytes());
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
// 若指定的 MD5 算法不存在,抛出运行时异常
|
|
|
throw new RuntimeException("没有这个md5算法!");
|
|
|
}
|
|
|
// 将加密后的字节数组转换为 16 进制字符串
|
|
|
String md5code = new BigInteger(1, secretBytes).toString(16);
|
|
|
// 补齐到 32 位
|
|
|
for (int i = 0; i < 32 - md5code.length(); i++) {
|
|
|
md5code = "0" + md5code;
|
|
|
}
|
|
|
return md5code;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 对密码进行加盐后的 MD5 加密。
|
|
|
*
|
|
|
* @param password 原始密码
|
|
|
* @return 加盐加密后的 MD5 字符串
|
|
|
*/
|
|
|
public static String passMd5(String password) {
|
|
|
// 定义盐值
|
|
|
String salt = "ew!.E";
|
|
|
// 将密码和盐值拼接后进行 MD5 加密并返回结果
|
|
|
return Util.stringToMD5(password + salt);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 主方法,用于测试 passMd5 方法。
|
|
|
*
|
|
|
* @param args 命令行参数
|
|
|
*/
|
|
|
public static void main(String[] args) {
|
|
|
// 打印对 "admin" 密码加盐加密后的 MD5 结果
|
|
|
System.out.println(Util.passMd5("admin"));
|
|
|
// 以下代码为注释掉的测试获取当前时间功能的代码
|
|
|
// Date date = new Date();
|
|
|
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
|
|
// System.out.println(dateFormat.format(date));
|
|
|
}
|
|
|
}
|
|
|
/*!
|
|
|
* classie - class helper functions
|
|
|
* from bonzo https://github.com/ded/bonzo
|
|
|
*
|
|
|
* classie.has( elem, 'my-class' ) -> true/false
|
|
|
* classie.add( elem, 'my-new-class' )
|
|
|
* classie.remove( elem, 'my-unwanted-class' )
|
|
|
* classie.toggle( elem, 'my-class' )
|
|
|
*/
|
|
|
|
|
|
/*jshint browser: true, strict: true, undef: true */
|
|
|
/*global define: false */
|
|
|
|
|
|
// 立即执行函数表达式 (IIFE),将 window 对象作为参数传入,避免全局作用域污染
|
|
|
( function( window ) {
|
|
|
|
|
|
// 使用严格模式,开启更严格的语法检查
|
|
|
'use strict';
|
|
|
|
|
|
// 从 bonzo 库借鉴的类操作辅助函数
|
|
|
// 该函数用于生成一个正则表达式,用于匹配元素类名中的指定类名
|
|
|
function classReg( className ) {
|
|
|
// 正则表达式解释:
|
|
|
// (^|\\s+) 匹配字符串的开头或者一个或多个空白字符
|
|
|
// className 是要匹配的类名
|
|
|
// (\\s+|$) 匹配一个或多个空白字符或者字符串的结尾
|
|
|
return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
|
|
|
}
|
|
|
|
|
|
// 用于管理元素类名的函数声明
|
|
|
// 这些函数将根据浏览器是否支持 classList 属性来实现不同的逻辑
|
|
|
var hasClass, addClass, removeClass;
|
|
|
|
|
|
// 检查浏览器是否支持 classList 属性
|
|
|
if ( 'classList' in document.documentElement ) {
|
|
|
// 如果支持 classList 属性
|
|
|
// hasClass 函数用于检查元素是否包含指定的类名
|
|
|
hasClass = function( elem, c ) {
|
|
|
// 使用 classList 的 contains 方法检查元素是否包含指定类名
|
|
|
return elem.classList.contains( c );
|
|
|
};
|
|
|
// addClass 函数用于给元素添加指定的类名
|
|
|
addClass = function( elem, c ) {
|
|
|
// 使用 classList 的 add 方法添加指定类名
|
|
|
elem.classList.add( c );
|
|
|
};
|
|
|
// removeClass 函数用于从元素中移除指定的类名
|
|
|
removeClass = function( elem, c ) {
|
|
|
// 使用 classList 的 remove 方法移除指定类名
|
|
|
elem.classList.remove( c );
|
|
|
};
|
|
|
}
|
|
|
else {
|
|
|
// 如果浏览器不支持 classList 属性
|
|
|
// hasClass 函数使用正则表达式来检查元素是否包含指定的类名
|
|
|
hasClass = function( elem, c ) {
|
|
|
// 使用 classReg 函数生成的正则表达式来测试元素的 className 属性
|
|
|
return classReg( c ).test( elem.className );
|
|
|
};
|
|
|
// addClass 函数用于给元素添加指定的类名
|
|
|
addClass = function( elem, c ) {
|
|
|
// 先检查元素是否已经包含指定的类名
|
|
|
if ( !hasClass( elem, c ) ) {
|
|
|
// 如果不包含,则在元素的 className 属性后面添加该类名
|
|
|
elem.className = elem.className + ' ' + c;
|
|
|
}
|
|
|
};
|
|
|
// removeClass 函数用于从元素中移除指定的类名
|
|
|
removeClass = function( elem, c ) {
|
|
|
// 使用 classReg 函数生成的正则表达式来替换元素 className 属性中的指定类名
|
|
|
elem.className = elem.className.replace( classReg( c ), ' ' );
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// toggleClass 函数用于切换元素的指定类名
|
|
|
function toggleClass( elem, c ) {
|
|
|
// 根据元素是否包含指定类名来选择调用 removeClass 或 addClass 函数
|
|
|
var fn = hasClass( elem, c ) ? removeClass : addClass;
|
|
|
// 调用选择的函数来切换类名
|
|
|
fn( elem, c );
|
|
|
}
|
|
|
|
|
|
// 创建一个 classie 对象,包含所有的类操作函数
|
|
|
var classie = {
|
|
|
// 完整的函数名
|
|
|
hasClass: hasClass,
|
|
|
addClass: addClass,
|
|
|
removeClass: removeClass,
|
|
|
toggleClass: toggleClass,
|
|
|
// 简短的函数名,方便使用
|
|
|
has: hasClass,
|
|
|
add: addClass,
|
|
|
remove: removeClass,
|
|
|
toggle: toggleClass
|
|
|
};
|
|
|
|
|
|
// 模块加载机制的处理
|
|
|
if ( typeof define === 'function' && define.amd ) {
|
|
|
// 如果使用 AMD 模块加载器(如 RequireJS),则使用 define 函数定义模块
|
|
|
define( classie );
|
|
|
} else {
|
|
|
// 如果没有使用 AMD 模块加载器,则将 classie 对象添加到 window 对象上,作为全局变量使用
|
|
|
window.classie = classie;
|
|
|
}
|
|
|
|
|
|
})( window );
|
|
|
/*!
|
|
|
* css-filters-polyfill.js
|
|
|
*
|
|
|
* Author: Christian Schepp Schaefer
|
|
|
* Summary: A polyfill for CSS filter effects
|
|
|
* License: MIT
|
|
|
* Version: 0.22
|
|
|
*
|
|
|
* URL:
|
|
|
* https://github.com/Schepp/
|
|
|
*
|
|
|
*/
|
|
|
// 立即执行函数表达式,将 window 对象作为参数传入,避免全局变量污染
|
|
|
;(function(window){
|
|
|
// 创建一个名为 polyfilter 的对象,用于封装所有与 CSS 滤镜填充相关的功能和属性
|
|
|
var polyfilter = {
|
|
|
// Detect if we are dealing with IE <= 9
|
|
|
// http://james.padolsey.com/javascript/detect-_ie-in-js-using-conditional-comments/
|
|
|
// 检测当前浏览器是否为 IE 9 及以下版本
|
|
|
_ie: (function(){
|
|
|
var undef;
|
|
|
// 初始化版本号为 3
|
|
|
var v = 3;
|
|
|
// 创建一个 div 元素
|
|
|
var div = document.createElement('div');
|
|
|
// 获取 div 元素内的所有 i 元素
|
|
|
var all = div.getElementsByTagName('i');
|
|
|
|
|
|
// 通过条件注释来检测 IE 版本
|
|
|
// 不断增加版本号 v,直到条件注释不满足(即当前 IE 版本不大于 v)
|
|
|
while(
|
|
|
// 设置 div 的 innerHTML 为条件注释
|
|
|
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
|
|
|
// 如果条件注释生效,会创建一个 i 元素,此时 all[0] 存在
|
|
|
all[0]
|
|
|
);
|
|
|
|
|
|
// 如果 v 大于 4,说明检测到了 IE 版本,返回该版本号;否则返回 undefined
|
|
|
return v > 4 ? v : undef;
|
|
|
})(),
|
|
|
|
|
|
// 用于缓存创建的 SVG 元素,避免重复创建
|
|
|
_svg_cache: {},
|
|
|
|
|
|
// 创建 SVG 元素的辅助函数
|
|
|
_create_svg_element: function(tagname,attributes){
|
|
|
// SVG 的命名空间
|
|
|
var xmlns = 'http://www.w3.org/2000/svg';
|
|
|
// 使用 createElementNS 方法创建 SVG 元素
|
|
|
var elem = document.createElementNS(xmlns,tagname);
|
|
|
// 遍历传入的属性对象
|
|
|
for(var key in attributes){
|
|
|
// 为 SVG 元素设置属性
|
|
|
elem.setAttributeNS(null,key,attributes[key]);
|
|
|
}
|
|
|
|
|
|
return elem;
|
|
|
},
|
|
|
|
|
|
// 创建完整 SVG 滤镜定义的函数
|
|
|
_create_svg: function(id,filterelements){
|
|
|
// SVG 的命名空间
|
|
|
var xmlns = 'http://www.w3.org/2000/svg';
|
|
|
// 创建一个 SVG 元素
|
|
|
var svg = document.createElementNS(xmlns,'svg');
|
|
|
// 设置 SVG 元素的宽度为 0
|
|
|
svg.setAttributeNS(null,'width','0');
|
|
|
// 设置 SVG 元素的高度为 0
|
|
|
svg.setAttributeNS(null,'height','0');
|
|
|
// 设置 SVG 元素的样式为绝对定位,避免影响页面布局
|
|
|
svg.setAttributeNS(null,'style','position:absolute');
|
|
|
|
|
|
// 创建一个 filter 元素
|
|
|
var svg_filter = document.createElementNS(xmlns,'filter');
|
|
|
// 为 filter 元素设置 id
|
|
|
svg_filter.setAttributeNS(null,'id',id);
|
|
|
// 将 filter 元素添加到 SVG 元素中
|
|
|
svg.appendChild(svg_filter);
|
|
|
|
|
|
// 遍历传入的滤镜元素数组
|
|
|
for(var i = 0; i < filterelements.length; i++){
|
|
|
// 将每个滤镜元素添加到 filter 元素中
|
|
|
svg_filter.appendChild(filterelements[i]);
|
|
|
}
|
|
|
|
|
|
return svg;
|
|
|
},
|
|
|
|
|
|
// 记录待处理的外部样式表数量
|
|
|
_pending_stylesheets: 0,
|
|
|
|
|
|
// 存储所有样式表(内联和外部)的信息
|
|
|
_stylesheets: [],
|
|
|
|
|
|
// 判断是否处于开发模式
|
|
|
_development_mode: (function(){
|
|
|
// 检查当前页面的主机名是否为 localhost 或者以 .local 结尾,或者是 IP 地址
|
|
|
if(location.hostname === 'localhost' || location.hostname.search(/.local$/) !== -1 || location.hostname.search(/\d+\.\d+\.\d+\.\d+/) !== -1){
|
|
|
// 如果处于开发模式,在控制台输出提示信息
|
|
|
if(window.console) console.log('Detected localhost or IP address. Assuming you are a developer. Caching of stylesheets is disabled.');
|
|
|
return true;
|
|
|
}
|
|
|
// 如果不是开发模式,在控制台输出提示信息
|
|
|
if(window.console) console.log('Caching of stylesheets is enabled. You need to refresh twice to see any changes.');
|
|
|
return false;
|
|
|
})(),
|
|
|
|
|
|
// 处理页面上所有样式表的函数
|
|
|
process_stylesheets: function(){
|
|
|
var xmlHttp = [];
|
|
|
|
|
|
// 延迟 2 秒后检查库文件路径是否正确,避免干扰初始处理
|
|
|
window.setTimeout(function(){
|
|
|
var xmlHttpCheck;
|
|
|
// 根据浏览器支持情况创建 XMLHttpRequest 对象
|
|
|
if (window.XMLHttpRequest) {
|
|
|
xmlHttpCheck = new XMLHttpRequest();
|
|
|
} else if (window.ActiveXObject) {
|
|
|
xmlHttpCheck = new ActiveXObject("Microsoft.XMLHTTP");
|
|
|
}
|
|
|
// 打开一个 GET 请求,检查 sepia.htc 文件是否存在
|
|
|
xmlHttpCheck.open('GET', window.polyfilter_scriptpath + 'htc/sepia.htc', true);
|
|
|
// 监听请求状态变化
|
|
|
xmlHttpCheck.onreadystatechange = function(){
|
|
|
// 当请求完成且状态码不是 200 时,说明路径可能有误
|
|
|
if(xmlHttpCheck.readyState == 4 && xmlHttpCheck.status != 200){
|
|
|
// 弹出提示框,提示用户配置正确的绝对路径
|
|
|
alert('The configured path \r\rvar polyfilter_scriptpath = "' + window.polyfilter_scriptpath + '"\r\rseems wrong!\r\rConfigure the polyfill\'s correct absolute(!) script path before referencing the css-filters-polyfill.js, like so:\r\rvar polyfilter_scriptpath = "/js/css-filters-polyfill/";\r\rLeaving IE dead in the water is no option. You damn Mac user... ;)');
|
|
|
}
|
|
|
};
|
|
|
try{
|
|
|
// 发送请求
|
|
|
xmlHttpCheck.send(null);
|
|
|
} catch(e){}
|
|
|
},2000);
|
|
|
|
|
|
// 获取页面上所有的样式表元素
|
|
|
var stylesheets = document.querySelectorAll ? document.querySelectorAll('style,link[rel="stylesheet"]') : document.getElementsByTagName('*');
|
|
|
|
|
|
// 遍历所有样式表元素
|
|
|
for(var i = 0; i < stylesheets.length; i++){
|
|
|
// 使用立即执行函数避免闭包问题
|
|
|
(function(i){
|
|
|
// 根据元素的节点名进行不同处理
|
|
|
switch(stylesheets[i].nodeName){
|
|
|
default:
|
|
|
// 如果节点名不是 STYLE 或 LINK,不做处理,直接跳出
|
|
|
break;
|
|
|
|
|
|
case 'STYLE':
|
|
|
// 当节点名是 STYLE 时,说明是内联样式表
|
|
|
polyfilter._stylesheets.push({
|
|
|
// 获取样式表的媒体查询属性,如果没有则默认为 'all'
|
|
|
media: stylesheets[i].media || 'all',
|
|
|
// 获取样式表的内容
|
|
|
content: stylesheets[i].innerHTML
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
case 'LINK':
|
|
|
// 当节点名是 LINK 时
|
|
|
if(stylesheets[i].rel === 'stylesheet'){
|
|
|
// 且该 LINK 元素的 rel 属性为 'stylesheet',说明是外部样式表
|
|
|
var index = polyfilter._stylesheets.length;
|
|
|
|
|
|
// 将该外部样式表的信息添加到 _stylesheets 数组中
|
|
|
polyfilter._stylesheets.push({
|
|
|
// 获取样式表的媒体查询属性,如果没有则默认为 'all'
|
|
|
media: stylesheets[i].media || 'all'
|
|
|
});
|
|
|
|
|
|
// 待处理的外部样式表数量加 1
|
|
|
polyfilter._pending_stylesheets++;
|
|
|
|
|
|
// 获取外部样式表的链接地址
|
|
|
var href = stylesheets[i].href;
|
|
|
|
|
|
// 如果不是开发模式,且浏览器支持 localStorage,并且 localStorage 中已经缓存了该样式表
|
|
|
if(!polyfilter._development_mode && window.localStorage && window.localStorage.getItem('polyfilter_' + href)){
|
|
|
// 待处理的外部样式表数量减 1
|
|
|
polyfilter._pending_stylesheets--;
|
|
|
// 从 localStorage 中获取缓存的样式表内容,并赋值给 _stylesheets 数组中对应的元素
|
|
|
polyfilter._stylesheets[index].content = localStorage.getItem('polyfilter_' + href);
|
|
|
// 如果所有待处理的外部样式表都已处理完毕
|
|
|
if(polyfilter._pending_stylesheets === 0){
|
|
|
// 调用 process 方法进行后续处理
|
|
|
polyfilter.process();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 无论是否有缓存,都要发起请求获取最新的样式表内容
|
|
|
try{
|
|
|
// 根据浏览器支持情况创建 XMLHttpRequest 对象
|
|
|
if(window.XMLHttpRequest) {
|
|
|
var xmlHttp = new XMLHttpRequest();
|
|
|
} else if(window.ActiveXObject) {
|
|
|
var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
|
|
|
}
|
|
|
// 打开一个 GET 请求,请求外部样式表
|
|
|
xmlHttp.open('GET', href, true);
|
|
|
// 监听请求状态变化
|
|
|
xmlHttp.onreadystatechange = function(){
|
|
|
// 当请求完成时
|
|
|
if(xmlHttp.readyState === 4){
|
|
|
// 如果状态码为 0,可能是跨域问题导致请求失败
|
|
|
if(xmlHttp.status === 0){
|
|
|
if(window.console) console.log('Could not fetch external CSS via HTTP-Request ' + href + '. Probably because of cross origin.');
|
|
|
// 如果 _stylesheets 数组中对应的元素还没有内容
|
|
|
if(!polyfilter._stylesheets[index].content){
|
|
|
// 待处理的外部样式表数量减 1
|
|
|
polyfilter._pending_stylesheets--;
|
|
|
// 将响应内容赋值给 _stylesheets 数组中对应的元素
|
|
|
polyfilter._stylesheets[index].content = xmlHttp.responseText;
|
|
|
// 如果所有待处理的外部样式表都已处理完毕
|
|
|
if(polyfilter._pending_stylesheets === 0){
|
|
|
// 调用 process 方法进行后续处理
|
|
|
polyfilter.process();
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
// 如果状态码正常
|
|
|
if(!polyfilter._stylesheets[index].content){
|
|
|
// 待处理的外部样式表数量减 1
|
|
|
polyfilter._pending_stylesheets--;
|
|
|
// 将响应内容赋值给 _stylesheets 数组中对应的元素
|
|
|
polyfilter._stylesheets[index].content = xmlHttp.responseText;
|
|
|
// 如果所有待处理的外部样式表都已处理完毕
|
|
|
if(polyfilter._pending_stylesheets === 0){
|
|
|
// 调用 process 方法进行后续处理
|
|
|
polyfilter.process();
|
|
|
}
|
|
|
}
|
|
|
// 如果不是开发模式,且浏览器支持 localStorage
|
|
|
if(!polyfilter._development_mode && window.localStorage){
|
|
|
try{
|
|
|
// 将样式表内容缓存到 localStorage 中
|
|
|
window.localStorage.setItem('polyfilter_' + href, polyfilter._stylesheets[index].content);
|
|
|
}
|
|
|
catch(e){
|
|
|
// 如果 localStorage 空间不足,输出提示信息
|
|
|
if(window.console) console.log('Local storage quota have been exceeded. Caching of stylesheet ' + href + ' is not possible');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
try{
|
|
|
// 发送请求
|
|
|
xmlHttp.send(null);
|
|
|
} catch(e){
|
|
|
// 如果请求发送失败,可能是使用 file:// 协议进行测试导致的
|
|
|
if(window.console) console.log('Could not fetch external CSS via HTTP-Request ' + href + '. Are you maybe testing using the file://-protocol?');
|
|
|
if(!polyfilter._stylesheets[index].content){
|
|
|
// 待处理的外部样式表数量减 1
|
|
|
polyfilter._pending_stylesheets--;
|
|
|
if(polyfilter._pending_stylesheets === 0){
|
|
|
// 调用 process 方法进行后续处理
|
|
|
polyfilter.process();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} catch(e){}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
})(i);
|
|
|
}
|
|
|
// 如果所有待处理的外部样式表都已处理完毕
|
|
|
if(this._pending_stylesheets === 0){
|
|
|
// 调用 process 方法进行后续处理
|
|
|
this.process();
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 处理 CSS 规则声明的函数
|
|
|
_processDeclarations: function(rule){
|
|
|
var newstyles = '';
|
|
|
// 遍历规则中的所有声明
|
|
|
for(var k in rule.declarations){
|
|
|
var declaration = rule.declarations[k];
|
|
|
|
|
|
// 如果声明的属性是 'filter'
|
|
|
if(declaration.property === 'filter'){
|
|
|
if(document.querySelectorAll){
|
|
|
// 检查浏览器是否支持 document.querySelectorAll 方法
|
|
|
// 使用选择器 rule.mSelectorText 获取匹配的元素集合
|
|
|
var elems = document.querySelectorAll(rule.mSelectorText);
|
|
|
for(var k = 0; k < elems.length; k++){
|
|
|
// 遍历匹配的元素集合,将当前 filter 声明的值存储到元素的 style.polyfilterStore 属性中
|
|
|
// 方便后续可能的使用
|
|
|
elems[k].style.polyfilterStore = declaration.valueText;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 获取 filter 属性声明的原始值
|
|
|
var gluedvalues = declaration.valueText;
|
|
|
// 将原始值按 ")" 后面跟着一个或多个空白字符进行分割,得到每个单独的滤镜值
|
|
|
var values = gluedvalues.split(/\)\s+/),
|
|
|
// 初始化一个对象,用于存储不同浏览器支持的滤镜属性值
|
|
|
properties = {
|
|
|
filtersW3C: [], // 存储 W3C 标准的滤镜属性值
|
|
|
filtersWebKit: [], // 存储 WebKit 内核浏览器(如 Safari、旧版 Chrome)的滤镜属性值
|
|
|
filtersSVG: [], // 存储 SVG 滤镜属性值
|
|
|
filtersIE: [], // 存储 Internet Explorer 浏览器的滤镜属性值
|
|
|
behaviorsIE: [] // 存储 Internet Explorer 浏览器的行为属性值(用于模拟滤镜效果)
|
|
|
};
|
|
|
|
|
|
// 遍历分割后的每个滤镜值
|
|
|
for(var idx in values){
|
|
|
var value = values[idx] + ')'; // 恢复完整的滤镜值
|
|
|
|
|
|
// 调用 polyfilter 对象的 convert 方法,将单个滤镜值转换为不同浏览器支持的属性值
|
|
|
var currentproperties = polyfilter.convert(value);
|
|
|
|
|
|
// 遍历转换后的属性值对象
|
|
|
for(var key in currentproperties){
|
|
|
if(typeof properties[key] !== 'undefined'){
|
|
|
// 如果当前属性在 properties 对象中存在,则将转换后的属性值追加到对应数组中
|
|
|
properties[key] = properties[key].concat(currentproperties[key]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 开始构建新的样式规则字符串,添加选择器和左花括号
|
|
|
newstyles += rule.mSelectorText + '{';
|
|
|
if(properties['filtersW3C'].length > 0){
|
|
|
// 如果存在 W3C 标准的滤镜属性值
|
|
|
var filter =
|
|
|
webkitFilter =
|
|
|
mozFilter =
|
|
|
oFilter =
|
|
|
msFilter =
|
|
|
properties['filtersW3C'].join(' '); // 将 W3C 标准的滤镜属性值用空格连接成一个字符串
|
|
|
|
|
|
if(properties['filtersWebKit'] && properties['filtersWebKit'].length > 0){
|
|
|
// 如果存在 WebKit 内核浏览器的滤镜属性值,则使用这些值替换 webkitFilter
|
|
|
webkitFilter = properties['filtersWebKit'].join(' ');
|
|
|
}
|
|
|
|
|
|
if(typeof this._ie === 'undefined'){
|
|
|
// 如果不是 Internet Explorer 浏览器,则添加 -ms-filter 属性
|
|
|
newstyles += '-ms-filter:' + msFilter + ';';
|
|
|
}
|
|
|
|
|
|
// 添加不同浏览器前缀的 filter 属性
|
|
|
newstyles += '-webkit-filter:' + webkitFilter + ';';
|
|
|
newstyles += '-moz-filter:' + mozFilter + ';';
|
|
|
newstyles += '-o-filter:' + oFilter + ';';
|
|
|
}
|
|
|
if(properties['filtersSVG'].length > 0){
|
|
|
if(properties['filtersSVG'][0] != 'none'){
|
|
|
// 如果 SVG 滤镜属性值不为 'none'
|
|
|
// 生成一个唯一的 ID,用于标识 SVG 滤镜
|
|
|
var id = gluedvalues.replace(/[^a-z0-9]/g,'');
|
|
|
|
|
|
if(typeof this._svg_cache[id] === 'undefined'){
|
|
|
// 如果 SVG 滤镜缓存中不存在该 ID 对应的 SVG 元素
|
|
|
// 创建一个新的 SVG 元素,并将其存储到缓存中
|
|
|
this._svg_cache[id] = this._create_svg(id,properties['filtersSVG']);
|
|
|
|
|
|
if(typeof XMLSerializer === 'undefined'){
|
|
|
// 如果浏览器不支持 XMLSerializer,则直接将 SVG 元素添加到 body 中
|
|
|
document.body.appendChild(this._svg_cache[id]);
|
|
|
}
|
|
|
else {
|
|
|
// 如果浏览器支持 XMLSerializer
|
|
|
var s = new XMLSerializer();
|
|
|
// 将 SVG 元素序列化为字符串
|
|
|
var svgString = s.serializeToString(this._svg_cache[id]);
|
|
|
if(svgString.search('SourceGraphic') != -1){
|
|
|
// 如果 SVG 字符串中包含 'SourceGraphic',则将 SVG 元素添加到 body 中
|
|
|
document.body.appendChild(this._svg_cache[id]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(typeof XMLSerializer === 'undefined'){
|
|
|
// 如果浏览器不支持 XMLSerializer,则使用 url(#id) 形式引用 SVG 滤镜
|
|
|
newstyles += 'filter: url(#' + id + ')';
|
|
|
}
|
|
|
else {
|
|
|
var s = new XMLSerializer();
|
|
|
// 将 SVG 元素序列化为字符串
|
|
|
var svgString = s.serializeToString(this._svg_cache[id]);
|
|
|
|
|
|
if(svgString.search('SourceGraphic') != -1){
|
|
|
// 如果 SVG 字符串中包含 'SourceGraphic',则使用 url(#id) 形式引用 SVG 滤镜
|
|
|
newstyles += 'filter: url(#' + id + ')';
|
|
|
}
|
|
|
else {
|
|
|
// 否则,使用 data URI 形式引用 SVG 滤镜
|
|
|
newstyles += 'filter: url(\'data:image/svg+xml;utf8,' + svgString + '#' + id + '\')';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
// 如果 SVG 滤镜属性值为 'none',则添加 filter: none;
|
|
|
newstyles += 'filter: none;';
|
|
|
}
|
|
|
}
|
|
|
if(typeof this._ie !== 'undefined'){
|
|
|
// 如果是 Internet Explorer 浏览器
|
|
|
if(properties['filtersIE'].length > 0){
|
|
|
// 如果存在 Internet Explorer 浏览器的滤镜属性值
|
|
|
var filtersIE = properties['filtersIE'].join(' ');
|
|
|
// 添加 filter 属性
|
|
|
newstyles += 'filter:' + filtersIE + ';';
|
|
|
}
|
|
|
if(properties['behaviorsIE'].length > 0){
|
|
|
// 如果存在 Internet Explorer 浏览器的行为属性值
|
|
|
var behaviorsIE = properties['behaviorsIE'].join(' ');
|
|
|
// 添加 behavior 属性
|
|
|
newstyles += 'behavior:' + behaviorsIE + ';';
|
|
|
}
|
|
|
}
|
|
|
// 完成当前选择器样式规则的构建,添加右花括号和换行符
|
|
|
newstyles += '}\r\n';
|
|
|
}
|
|
|
}
|
|
|
// 返回新生成的样式规则字符串
|
|
|
return newstyles;
|
|
|
},
|
|
|
|
|
|
// 存储 .htc 文件的绝对路径
|
|
|
scriptpath: window.polyfilter_scriptpath ? window.polyfilter_scriptpath : (function(){
|
|
|
// 如果没有在 window 对象中配置 polyfilter_scriptpath
|
|
|
// 弹出提示框,提醒用户在引用 css - filters - polyfill.js 之前配置正确的绝对路径
|
|
|
alert('Please configure the polyfill\'s absolute(!) script path before referencing the css-filters-polyfill.js, like so:\r\nvar polyfilter_scriptpath = "/js/css-filters-polyfill/";');
|
|
|
// 默认返回当前目录
|
|
|
return './'
|
|
|
})(),
|
|
|
|
|
|
// 处理样式表的主函数
|
|
|
process: function(){
|
|
|
// 创建一个 CSS 解析器实例
|
|
|
var parser = new CSSParser();
|
|
|
|
|
|
// 遍历存储的所有样式表
|
|
|
for(var i = 0; i < this._stylesheets.length; i++){
|
|
|
// 初始化新样式字符串
|
|
|
var newstyles = '';
|
|
|
// 使用解析器解析当前样式表的内容
|
|
|
var sheet = parser.parse(this._stylesheets[i].content, false, true);
|
|
|
// 如果解析结果不为空
|
|
|
if(sheet !== null) for(var j in sheet.cssRules){
|
|
|
var rule = sheet.cssRules[j];
|
|
|
|
|
|
// 根据规则类型进行不同处理
|
|
|
switch(rule.type){
|
|
|
default:
|
|
|
// 默认情况不做处理
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
// 类型 1 通常表示普通的样式规则
|
|
|
// 调用 _processDeclarations 方法处理该规则,并将结果添加到新样式字符串中
|
|
|
newstyles += this._processDeclarations(rule);
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
// 类型 4 通常表示 @media 媒体查询规则
|
|
|
// 构建媒体查询的开头部分
|
|
|
newstyles += '@media ' + rule.media.join(',') + '{';
|
|
|
// 遍历媒体查询内的子规则
|
|
|
for(var k in rule.cssRules){
|
|
|
var mediarule = rule.cssRules[k];
|
|
|
// 调用 _processDeclarations 方法处理子规则,并将结果添加到新样式字符串中
|
|
|
newstyles += this._processDeclarations(mediarule);
|
|
|
}
|
|
|
// 构建媒体查询的结尾部分
|
|
|
newstyles += '}';
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 创建一个新的 <style> 元素
|
|
|
var newstylesheet = document.createElement('style');
|
|
|
// 设置该 <style> 元素的媒体属性
|
|
|
newstylesheet.setAttribute('media',this._stylesheets[i].media);
|
|
|
|
|
|
if(typeof polyfilter._ie === 'undefined'){
|
|
|
// 如果不是 IE 浏览器
|
|
|
// 将新生成的样式字符串设置为 <style> 元素的 innerHTML
|
|
|
newstylesheet.innerHTML = newstyles;
|
|
|
// 将 <style> 元素添加到 <head> 标签中
|
|
|
document.getElementsByTagName('head')[0].appendChild(newstylesheet);
|
|
|
}
|
|
|
else {
|
|
|
// 如果是 IE 浏览器
|
|
|
// 将 <style> 元素添加到 <head> 标签中
|
|
|
document.getElementsByTagName('head')[0].appendChild(newstylesheet);
|
|
|
// 使用 styleSheet.cssText 属性设置样式内容
|
|
|
newstylesheet.styleSheet.cssText = newstyles;
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 初始化函数,用于给 CSSStyleDeclaration 原型添加自定义属性
|
|
|
init: function(){
|
|
|
if(Object.defineProperty){
|
|
|
// 如果浏览器支持 Object.defineProperty 方法
|
|
|
// 给 CSSStyleDeclaration 原型添加一个名为 'polyfilter' 的属性
|
|
|
Object.defineProperty(CSSStyleDeclaration.prototype, 'polyfilter', {
|
|
|
// 定义获取属性值的方法
|
|
|
get: function(){
|
|
|
// 返回之前存储在 polyfilterStore 中的值
|
|
|
return this.polyfilterStore;
|
|
|
},
|
|
|
// 定义设置属性值的方法
|
|
|
set: function(gluedvalues){
|
|
|
// 将传入的滤镜值按 ")" 后面跟着一个或多个空白字符进行分割
|
|
|
values = gluedvalues.split(/\)\s+/);
|
|
|
var properties = {
|
|
|
filtersW3C: [],
|
|
|
filtersWebKit: [],
|
|
|
filtersSVG: [],
|
|
|
filtersIE: [],
|
|
|
behaviorsIE: []
|
|
|
}
|
|
|
|
|
|
// 遍历分割后的每个滤镜值
|
|
|
for(var idx in values){
|
|
|
var value = values[idx] + ')';
|
|
|
// 调用 convert 方法将单个滤镜值转换为不同浏览器支持的属性值
|
|
|
var currentproperties = polyfilter.convert(value);
|
|
|
|
|
|
// 遍历转换后的属性值对象
|
|
|
for(var key in currentproperties){
|
|
|
if(typeof properties[key] !== 'undefined'){
|
|
|
// 将转换后的属性值追加到对应数组中
|
|
|
properties[key] = properties[key].concat(currentproperties[key]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(properties['filtersW3C'].length > 0){
|
|
|
if(typeof polyfilter._ie === 'undefined'){
|
|
|
// 如果不是 IE 浏览器,设置 -ms-filter 属性
|
|
|
this.msFilter = properties['filtersW3C'].join(' ');
|
|
|
}
|
|
|
// 设置不同浏览器前缀的 filter 属性
|
|
|
this.webkitFilter =
|
|
|
this.mozFilter =
|
|
|
this.oFilter = properties['filtersW3C'].join(' ');
|
|
|
}
|
|
|
if(properties['filtersWebKit'].length > 0){
|
|
|
// 如果有 WebKit 特定的滤镜值,优先使用
|
|
|
this.webkitFilter = properties['filtersWebKit'].join(' ');
|
|
|
}
|
|
|
if(properties['filtersSVG'].length > 0){
|
|
|
if(properties['filtersSVG'][0] != 'none'){
|
|
|
// 生成一个唯一的 ID,去除滤镜值字符串中的非字母数字字符
|
|
|
var id = gluedvalues.replace(/[^a-z0-9]/g,'');
|
|
|
|
|
|
// 检查 SVG 滤镜缓存中是否已经存在该 ID 对应的 SVG 滤镜
|
|
|
if(typeof polyfilter._svg_cache[id] === 'undefined'){
|
|
|
// 若不存在,创建一个新的 SVG 滤镜并缓存起来
|
|
|
polyfilter._svg_cache[id] = polyfilter._create_svg(id,properties['filtersSVG']);
|
|
|
|
|
|
// 检查浏览器是否支持 XMLSerializer 对象
|
|
|
if(typeof XMLSerializer === 'undefined'){
|
|
|
// 若不支持,直接将 SVG 滤镜添加到页面的 body 元素中
|
|
|
document.body.appendChild(polyfilter._svg_cache[id]);
|
|
|
}
|
|
|
else {
|
|
|
// 若支持,将 SVG 滤镜序列化为字符串
|
|
|
var s = new XMLSerializer();
|
|
|
var svgString = s.serializeToString(polyfilter._svg_cache[id]);
|
|
|
// 检查序列化后的 SVG 字符串中是否包含 'SourceGraphic'
|
|
|
if(svgString.search('SourceGraphic') != -1){
|
|
|
// 若包含,将 SVG 滤镜添加到页面的 body 元素中
|
|
|
document.body.appendChild(polyfilter._svg_cache[id]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 再次检查浏览器是否支持 XMLSerializer 对象
|
|
|
if(typeof XMLSerializer === 'undefined'){
|
|
|
// 若不支持,使用 url(#id) 的形式引用 SVG 滤镜
|
|
|
this.filter = 'url(#' + id + ')';
|
|
|
}
|
|
|
else {
|
|
|
// 若支持,将 SVG 滤镜再次序列化为字符串
|
|
|
var s = new XMLSerializer();
|
|
|
var svgString = s.serializeToString(polyfilter._svg_cache[id]);
|
|
|
// 检查序列化后的 SVG 字符串中是否包含 'SourceGraphic'
|
|
|
if(svgString.search('SourceGraphic') != -1){
|
|
|
// 若包含,使用 url(#id) 的形式引用 SVG 滤镜
|
|
|
this.filter = 'url(#' + id + ')';
|
|
|
}
|
|
|
else {
|
|
|
// 若不包含,使用 data URI 的形式引用 SVG 滤镜
|
|
|
this.filter = 'url(\'data:image/svg+xml;utf8,' + svgString + '#' + id + '\')';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
// 如果 SVG 滤镜属性值为 'none',则设置 filter 属性为 'none'
|
|
|
this.filter = 'none';
|
|
|
}
|
|
|
|
|
|
// 检查当前浏览器是否为 IE
|
|
|
if(typeof polyfilter._ie !== 'undefined'){
|
|
|
if(properties['filtersIE'].length > 0){
|
|
|
// 如果存在 IE 支持的滤镜属性,将其连接成字符串并赋值给 filter 属性
|
|
|
this.filter = properties['filtersIE'].join(' ');
|
|
|
}
|
|
|
else {
|
|
|
// 若不存在,清空 filter 属性
|
|
|
this.filter = '';
|
|
|
}
|
|
|
if(properties['behaviorsIE'].length > 0){
|
|
|
// 如果存在 IE 支持的行为属性,将其连接成字符串并赋值给 behavior 属性
|
|
|
this.behavior = properties['behaviorsIE'].join(' ');
|
|
|
}
|
|
|
else {
|
|
|
// 若不存在,清空 behavior 属性
|
|
|
this.behavior = '';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 将传入的滤镜值存储到 polyfilterStore 属性中,方便后续获取
|
|
|
this.polyfilterStore = gluedvalues;
|
|
|
}
|
|
|
}),
|
|
|
get: function(){
|
|
|
// 定义获取 polyfilter 属性值的方法,返回存储的滤镜值
|
|
|
return this.polyfilterStore;
|
|
|
},
|
|
|
set: function(gluedvalues){
|
|
|
// 定义设置 polyfilter 属性值的方法
|
|
|
values = gluedvalues.split(/\)\s+/);
|
|
|
var properties = {
|
|
|
filtersW3C: [],
|
|
|
filtersWebKit: [],
|
|
|
filtersSVG: [],
|
|
|
filtersIE: [],
|
|
|
behaviorsIE: []
|
|
|
}
|
|
|
|
|
|
// 遍历分割后的每个滤镜值
|
|
|
for(idx in values){
|
|
|
var value = values[idx] + ')';
|
|
|
// 调用 convert 方法将单个滤镜值转换为不同浏览器支持的属性值
|
|
|
currentproperties = polyfilter.convert(value);
|
|
|
|
|
|
// 将转换后的属性值追加到对应数组中
|
|
|
for(key in currentproperties){
|
|
|
if(typeof properties[key] !== 'undefined'){
|
|
|
properties[key] = properties[key].concat(currentproperties[key]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(properties['filtersW3C'].length > 0){
|
|
|
if(typeof polyfilter._ie === 'undefined'){
|
|
|
// 如果不是 IE 浏览器,设置 -ms-filter 属性
|
|
|
this.msFilter = properties['filtersW3C'].join(' ');
|
|
|
}
|
|
|
// 设置不同浏览器前缀的 filter 属性
|
|
|
this.webkitFilter =
|
|
|
this.mozFilter =
|
|
|
this.oFilter = properties['filtersW3C'].join(' ');
|
|
|
}
|
|
|
if(properties['filtersWebKit'].length > 0){
|
|
|
// 如果有 WebKit 特定的滤镜值,优先使用
|
|
|
this.webkitFilter = properties['filtersWebKit'].join(' ');
|
|
|
}
|
|
|
if(properties['filtersSVG'].length > 0){
|
|
|
if(properties['filtersSVG'][0] != 'none'){
|
|
|
// 生成一个唯一的 ID,用于标识 SVG 滤镜
|
|
|
var id = gluedvalues.replace(/[^a-z0-9]/g,'');
|
|
|
|
|
|
if(typeof polyfilter._svg_cache[id] === 'undefined'){
|
|
|
// 如果 SVG 滤镜缓存中不存在该 ID 对应的 SVG 元素
|
|
|
polyfilter._svg_cache[id] = polyfilter._create_svg(id,properties['filtersSVG']);
|
|
|
|
|
|
if(typeof XMLSerializer === 'undefined'){
|
|
|
// 如果浏览器不支持 XMLSerializer,将 SVG 元素添加到 body 中
|
|
|
document.body.appendChild(polyfilter._svg_cache[id]);
|
|
|
}
|
|
|
else {
|
|
|
var s = new XMLSerializer();
|
|
|
var svgString = s.serializeToString(polyfilter._svg_cache[id]);
|
|
|
if(svgString.search('SourceGraphic') != -1){
|
|
|
// 如果 SVG 字符串中包含 'SourceGraphic',将 SVG 元素添加到 body 中
|
|
|
document.body.appendChild(polyfilter._svg_cache[id]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(typeof XMLSerializer === 'undefined'){
|
|
|
// 如果浏览器不支持 XMLSerializer,使用 url(#id) 形式引用 SVG 滤镜
|
|
|
this.filter = 'url(#' + id + ')';
|
|
|
}
|
|
|
else {
|
|
|
var s = new XMLSerializer();
|
|
|
var svgString = s.serializeToString(polyfilter._svg_cache[id]);
|
|
|
if(svgString.search('SourceGraphic') != -1){
|
|
|
// 如果 SVG 字符串中包含 'SourceGraphic',使用 url(#id) 形式引用 SVG 滤镜
|
|
|
this.filter = 'url(#' + id + ')';
|
|
|
}
|
|
|
else {
|
|
|
// 否则,使用 data URI 形式引用 SVG 滤镜
|
|
|
this.filter = 'url(\'data:image/svg+xml;utf8,' + svgString + '#' + id + '\')';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
// 如果 SVG 滤镜属性值为 'none',则设置 filter 属性为 'none'
|
|
|
this.filter = 'none';
|
|
|
}
|
|
|
}
|
|
|
if(typeof polyfilter._ie !== 'undefined'){
|
|
|
if(properties['filtersIE'].length > 0){
|
|
|
// 如果存在 IE 支持的滤镜属性,设置 filter 属性
|
|
|
this.filter = properties['filtersIE'].join(' ');
|
|
|
}
|
|
|
if(properties['behaviorsIE'].length > 0){
|
|
|
// 如果存在 IE 支持的行为属性,设置 behavior 属性
|
|
|
this.behavior = properties['behaviorsIE'].join(' ');
|
|
|
}
|
|
|
}
|
|
|
// 存储原始的滤镜值,方便后续获取
|
|
|
this.polyfilterStore = gluedvalues;
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 将传入的滤镜值转换为不同浏览器支持的属性值
|
|
|
convert: function(value){
|
|
|
// 检查是否为 'none' 滤镜
|
|
|
var fmatch = value.match(/none/i);
|
|
|
if(fmatch !== null){
|
|
|
var properties = this.filters.none();
|
|
|
}
|
|
|
// 检查是否为 'grayscale' 滤镜
|
|
|
var fmatch = value.match(/(grayscale)\(([0-9\.]+)\)/i);
|
|
|
if(fmatch !== null){
|
|
|
var amount = parseFloat(fmatch[2],10);
|
|
|
var properties = this.filters.grayscale(amount);
|
|
|
}
|
|
|
// 检查是否为 'sepia' 滤镜
|
|
|
var fmatch = value.match(/(sepia)\(([0-9\.]+)\)/i);
|
|
|
if(fmatch !== null){
|
|
|
var amount = parseFloat(fmatch[2],10);
|
|
|
var properties = this.filters.sepia(amount);
|
|
|
}
|
|
|
// 检查是否为 'blur' 滤镜
|
|
|
var fmatch = value.match(/(blur)\(([0-9]+)[px]*\)/i);
|
|
|
if(fmatch !== null){
|
|
|
var amount = parseInt(fmatch[2],10);
|
|
|
var properties = this.filters.blur(amount);
|
|
|
}
|
|
|
// 检查是否为 'brightness' 滤镜
|
|
|
var fmatch = value.match(/(brightness)\(([0-9\.]+)%\)/i);
|
|
|
if(fmatch !== null){
|
|
|
var amount = parseFloat(fmatch[2],10);
|
|
|
var properties = this.filters.brightness(amount);
|
|
|
}
|
|
|
// 检查是否为 'drop-shadow' 滤镜
|
|
|
var fmatch = value.match(/(drop\-shadow)\(([0-9]+)[px]*\s+([0-9]+)[px]*\s+([0-9]+)[px]*\s+([\#0-9]+)\)/i);
|
|
|
if(fmatch !== null){
|
|
|
var offsetX = parseInt(fmatch[2],10);
|
|
|
var offsetY = parseInt(fmatch[3],10);
|
|
|
var radius = parseInt(fmatch[4],10);
|
|
|
var color = fmatch[5];
|
|
|
var properties = this.filters.dropShadow(offsetX,offsetY,radius,color);
|
|
|
}
|
|
|
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 定义各种滤镜效果的处理函数
|
|
|
filters: {
|
|
|
// 'none' 滤镜效果
|
|
|
none: function(){
|
|
|
var properties = {};
|
|
|
if(typeof polyfilter._ie === 'undefined'){
|
|
|
// 非 IE 浏览器,设置 W3C 标准和 SVG 滤镜属性为 'none'
|
|
|
properties['filtersW3C'] = ['none'];
|
|
|
properties['filtersSVG'] = ['none'];
|
|
|
}
|
|
|
else {
|
|
|
// IE 浏览器,设置 IE 支持的滤镜属性为 'none'
|
|
|
properties['filtersIE'] = ['none'];
|
|
|
}
|
|
|
return properties;
|
|
|
},
|
|
|
// 'grayscale' 灰度滤镜效果
|
|
|
grayscale: function(amount){
|
|
|
amount = amount || 0;
|
|
|
var properties = {};
|
|
|
if(typeof polyfilter._ie === 'undefined'){
|
|
|
// 非 IE 浏览器,设置 W3C 标准的灰度滤镜属性
|
|
|
properties['filtersW3C'] = ['grayscale(' + amount + ')'];
|
|
|
// 创建 SVG 滤镜元素
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feColorMatrix',{
|
|
|
type: 'matrix',
|
|
|
values: (0.2126 + 0.7874 * (1 - amount)) + ' '
|
|
|
+ (0.7152 - 0.7152 * (1 - amount)) + ' '
|
|
|
+ (0.0722 - 0.0722 * (1 - amount)) + ' 0 0 '
|
|
|
+ (0.2126 - 0.2126 * (1 - amount)) + ' '
|
|
|
+ (0.7152 + 0.2848 * (1 - amount)) + ' '
|
|
|
+ (0.0722 - 0.0722 * (1 - amount)) + ' 0 0 '
|
|
|
+ (0.2126 - 0.2126 * (1 - amount)) + ' '
|
|
|
+ (0.7152 - 0.7152 * (1 - amount)) + ' '
|
|
|
+ (0.0722 + 0.9278 * (1 - amount)) + ' 0 0 0 0 0 1 0'
|
|
|
});
|
|
|
properties['filtersSVG'] = [svg_fe1];
|
|
|
}
|
|
|
else {
|
|
|
// IE 浏览器,根据灰度值决定是否应用 'gray' 滤镜
|
|
|
properties['filtersIE'] = amount >= 0.5 ? ['gray'] : [];
|
|
|
}
|
|
|
return properties;
|
|
|
},
|
|
|
// 其他滤镜效果(sepia、blur、invert、brightness、dropShadow)的处理逻辑类似,分别根据不同浏览器和参数设置相应的属性值
|
|
|
// ...
|
|
|
}
|
|
|
// 定义滤镜处理对象,包含各种滤镜效果的处理方法
|
|
|
filters: {
|
|
|
// 无滤镜效果处理函数
|
|
|
none: function() {
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置无滤镜效果
|
|
|
properties['filtersW3C'] = ['none'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现无滤镜效果
|
|
|
properties['filtersSVG'] = ['none'];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,设置 IE 特定的无滤镜效果
|
|
|
properties['filtersIE'] = ['none'];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 灰度滤镜效果处理函数
|
|
|
grayscale: function(amount) {
|
|
|
// 如果未传入灰度值,默认为 0
|
|
|
amount = amount || 0;
|
|
|
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置灰度滤镜效果及对应强度
|
|
|
properties['filtersW3C'] = ['grayscale(' + amount + ')'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现灰度滤镜效果
|
|
|
// 参考文档:https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feColorMatrix', {
|
|
|
type: 'matrix',
|
|
|
// 根据灰度值计算颜色矩阵的值
|
|
|
values: (0.2126 + 0.7874 * (1 - amount)) + ' '
|
|
|
+ (0.7152 - 0.7152 * (1 - amount)) + ' '
|
|
|
+ (0.0722 - 0.0722 * (1 - amount)) + ' 0 0 '
|
|
|
+ (0.2126 - 0.2126 * (1 - amount)) + ' '
|
|
|
+ (0.7152 + 0.2848 * (1 - amount)) + ' '
|
|
|
+ (0.0722 - 0.0722 * (1 - amount)) + ' 0 0 '
|
|
|
+ (0.2126 - 0.2126 * (1 - amount)) + ' '
|
|
|
+ (0.7152 - 0.7152 * (1 - amount)) + ' '
|
|
|
+ (0.0722 + 0.9278 * (1 - amount)) + ' 0 0 0 0 0 1 0'
|
|
|
});
|
|
|
properties['filtersSVG'] = [svg_fe1];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,当灰度值大于等于 0.5 时,应用灰度滤镜
|
|
|
properties['filtersIE'] = amount >= 0.5 ? ['gray'] : [];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 棕褐色滤镜效果处理函数
|
|
|
sepia: function(amount) {
|
|
|
// 如果未传入棕褐色强度值,默认为 0
|
|
|
amount = amount || 0;
|
|
|
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置棕褐色滤镜效果及对应强度
|
|
|
properties['filtersW3C'] = ['sepia(' + amount + ')'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现棕褐色滤镜效果
|
|
|
// 参考文档:https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feColorMatrix', {
|
|
|
type: 'matrix',
|
|
|
// 根据棕褐色强度值计算颜色矩阵的值
|
|
|
values: (0.393 + 0.607 * (1 - amount)) + ' '
|
|
|
+ (0.769 - 0.769 * (1 - amount)) + ' '
|
|
|
+ (0.189 - 0.189 * (1 - amount)) + ' 0 0 '
|
|
|
+ (0.349 - 0.349 * (1 - amount)) + ' '
|
|
|
+ (0.686 + 0.314 * (1 - amount)) + ' '
|
|
|
+ (0.168 - 0.168 * (1 - amount)) + ' 0 0 '
|
|
|
+ (0.272 - 0.272 * (1 - amount)) + ' '
|
|
|
+ (0.534 - 0.534 * (1 - amount)) + ' '
|
|
|
+ (0.131 + 0.869 * (1 - amount)) + ' 0 0 0 0 0 1 0'
|
|
|
});
|
|
|
properties['filtersSVG'] = [svg_fe1];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,当棕褐色强度值大于等于 0.5 时,应用灰度滤镜和光照效果
|
|
|
properties['filtersIE'] = amount >= 0.5 ? ['gray', 'progid:DXImageTransform.Microsoft.Light()'] : [];
|
|
|
// 当棕褐色强度值大于等于 0.5 时,引入棕褐色效果的 HTC 文件
|
|
|
properties['behaviorsIE'] = amount >= 0.5 ? ['url("' + polyfilter.scriptpath + 'htc/sepia.htc")'] : [];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 模糊滤镜效果处理函数
|
|
|
blur: function(amount) {
|
|
|
// 对模糊半径进行四舍五入取整,如果未传入则默认为 0
|
|
|
amount = Math.round(amount) || 0;
|
|
|
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置模糊滤镜效果及对应半径
|
|
|
properties['filtersW3C'] = ['blur(' + amount + 'px)'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现模糊滤镜效果
|
|
|
// 参考文档:https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feGaussianBlur', {
|
|
|
'in': 'SourceGraphic',
|
|
|
stdDeviation: amount
|
|
|
});
|
|
|
properties['filtersSVG'] = [svg_fe1];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,设置 IE 特定的模糊滤镜效果
|
|
|
properties['filtersIE'] = ['progid:DXImageTransform.Microsoft.Blur(pixelradius=' + amount + ')'];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 反相滤镜效果处理函数
|
|
|
invert: function(amount) {
|
|
|
// 如果未传入反相强度值,默认为 0
|
|
|
amount = amount || 0;
|
|
|
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置反相滤镜效果及对应强度
|
|
|
properties['filtersW3C'] = ['invert(' + amount + ')'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现反相滤镜效果
|
|
|
// 参考文档:https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feComponentTransfer', {});
|
|
|
var svg_fe1sub = polyfilter._create_svg_element('feFuncR', {
|
|
|
type: 'table',
|
|
|
tableValues: amount + ' ' + (1 - amount)
|
|
|
});
|
|
|
svg_fe1.appendChild(svg_fe1sub);
|
|
|
var svg_fe1sub = polyfilter._create_svg_element('feFuncG', {
|
|
|
type: 'table',
|
|
|
tableValues: amount + ' ' + (1 - amount)
|
|
|
});
|
|
|
svg_fe1.appendChild(svg_fe1sub);
|
|
|
var svg_fe1sub = polyfilter._create_svg_element('feFuncB', {
|
|
|
type: 'table',
|
|
|
tableValues: amount + ' ' + (1 - amount)
|
|
|
});
|
|
|
svg_fe1.appendChild(svg_fe1sub);
|
|
|
properties['filtersSVG'] = [svg_fe1];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,当反相强度值大于等于 0.5 时,应用反相滤镜
|
|
|
properties['filtersIE'] = amount >= 0.5 ? ['invert'] : [];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 亮度滤镜效果处理函数
|
|
|
brightness: function(amount) {
|
|
|
// 如果未传入亮度值,默认为 0
|
|
|
amount = amount || 0;
|
|
|
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置亮度滤镜效果及对应亮度值
|
|
|
properties['filtersW3C'] = ['brightness(' + amount + '%)'];
|
|
|
|
|
|
// WebKit 内核浏览器的特殊处理
|
|
|
properties['filtersWebKit'] = ['brightness(' + (amount - 100) + '%)'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现亮度滤镜效果
|
|
|
// 参考文档:https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feComponentTransfer', {});
|
|
|
var svg_fe1sub = polyfilter._create_svg_element('feFuncR', {
|
|
|
type: 'linear',
|
|
|
slope: amount / 100
|
|
|
});
|
|
|
svg_fe1.appendChild(svg_fe1sub);
|
|
|
var svg_fe1sub = polyfilter._create_svg_element('feFuncG', {
|
|
|
type: 'linear',
|
|
|
slope: amount / 100
|
|
|
});
|
|
|
svg_fe1.appendChild(svg_fe1sub);
|
|
|
var svg_fe1sub = polyfilter._create_svg_element('feFuncB', {
|
|
|
type: 'linear',
|
|
|
slope: amount / 100
|
|
|
});
|
|
|
svg_fe1.appendChild(svg_fe1sub);
|
|
|
properties['filtersSVG'] = [svg_fe1];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,设置 IE 特定的光照效果滤镜
|
|
|
properties['filtersIE'] = ['progid:DXImageTransform.Microsoft.Light()'];
|
|
|
// 引入亮度效果的 HTC 文件
|
|
|
properties['behaviorsIE'] = ['url("' + polyfilter.scriptpath + 'htc/brightness.htc")'];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
},
|
|
|
|
|
|
// 投影滤镜效果处理函数
|
|
|
dropShadow: function(offsetX, offsetY, radius, color) {
|
|
|
// 对投影的 X 轴偏移量进行四舍五入取整,如果未传入则默认为 0
|
|
|
offsetX = Math.round(offsetX) || 0;
|
|
|
// 对投影的 Y 轴偏移量进行四舍五入取整,如果未传入则默认为 0
|
|
|
offsetY = Math.round(offsetY) || 0;
|
|
|
// 对投影的模糊半径进行四舍五入取整,如果未传入则默认为 0
|
|
|
radius = Math.round(radius) || 0;
|
|
|
// 如果未传入投影颜色,默认为黑色
|
|
|
color = color || '#000000';
|
|
|
|
|
|
// 初始化一个空对象,用于存储不同浏览器的滤镜属性
|
|
|
var properties = {};
|
|
|
|
|
|
// 检查是否不是 IE 浏览器
|
|
|
if (typeof polyfilter._ie === 'undefined') {
|
|
|
// 按照 W3C 标准提案,设置投影滤镜效果及对应参数
|
|
|
properties['filtersW3C'] = ['drop-shadow(' + offsetX + 'px ' + offsetY + 'px ' + radius + 'px ' + color + ')'];
|
|
|
|
|
|
// 针对 Firefox 浏览器,使用 SVG 实现投影滤镜效果
|
|
|
// 参考文档:https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
|
|
var svg_fe1 = polyfilter._create_svg_element('feGaussianBlur', {
|
|
|
'in': 'SourceAlpha',
|
|
|
stdDeviation: radius
|
|
|
});
|
|
|
var svg_fe2 = polyfilter._create_svg_element('feOffset', {
|
|
|
dx: offsetX + 1,
|
|
|
dy: offsetY + 1,
|
|
|
result: 'offsetblur'
|
|
|
});
|
|
|
var svg_fe3 = polyfilter._create_svg_element('feFlood', {
|
|
|
'flood-color': color
|
|
|
});
|
|
|
var svg_fe4 = polyfilter._create_svg_element('feComposite', {
|
|
|
in2: 'offsetblur',
|
|
|
operator: 'in'
|
|
|
});
|
|
|
var svg_fe5 = polyfilter._create_svg_element('feMerge', {});
|
|
|
var svg_fe5sub = polyfilter._create_svg_element('feMergeNode', {});
|
|
|
svg_fe5.appendChild(svg_fe5sub);
|
|
|
var svg_fe5sub = polyfilter._create_svg_element('feMergeNode', {
|
|
|
'in': 'SourceGraphic'
|
|
|
});
|
|
|
svg_fe5.appendChild(svg_fe5sub);
|
|
|
properties['filtersSVG'] = [svg_fe1, svg_fe2, svg_fe3, svg_fe4, svg_fe5];
|
|
|
} else {
|
|
|
// 如果是 IE 浏览器,设置 IE 特定的发光和阴影效果滤镜
|
|
|
properties['filtersIE'] = ['progid:DXImageTransform.Microsoft.Glow(color=' + color + ',strength=0)', 'progid:DXImageTransform.Microsoft.Shadow(color=' + color + ',strength=0)'];
|
|
|
// 引入投影效果的 HTC 文件
|
|
|
properties['behaviorsIE'] = ['url("' + polyfilter.scriptpath + 'htc/drop-shadow.htc")'];
|
|
|
}
|
|
|
|
|
|
// 返回包含不同浏览器滤镜属性的对象
|
|
|
return properties;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 初始化部分,根据不同的情况调用处理样式表的方法
|
|
|
// 如果页面中引入了 jQuery 库
|
|
|
if (window.jQuery) {
|
|
|
// 当文档准备好时,调用 polyfilter 对象的 process_stylesheets 方法处理样式表
|
|
|
window.jQuery(document).ready(function (e) {
|
|
|
polyfilter.process_stylesheets();
|
|
|
});
|
|
|
}
|
|
|
// 如果页面中存在 contentLoaded 函数
|
|
|
else if (window.contentLoaded) {
|
|
|
// 当页面内容加载完成后,调用 polyfilter 对象的 process_stylesheets 方法处理样式表
|
|
|
contentLoaded(window, function () {
|
|
|
polyfilter.process_stylesheets();
|
|
|
});
|
|
|
}
|
|
|
// 其他情况
|
|
|
else {
|
|
|
// 如果浏览器支持 addEventListener 方法(W3C 标准)
|
|
|
if (window.addEventListener) {
|
|
|
// 当 DOM 内容加载完成后,调用 polyfilter 对象的 process_stylesheets 方法处理样式表
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
polyfilter.process_stylesheets();
|
|
|
}, false);
|
|
|
}
|
|
|
// 如果浏览器支持 attachEvent 方法(Microsoft 标准)
|
|
|
else if (window.attachEvent) {
|
|
|
// 当页面加载完成后,调用 polyfilter 对象的 process_stylesheets 方法处理样式表
|
|
|
window.attachEvent('onload', function () {
|
|
|
polyfilter.process_stylesheets();
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 调用 polyfilter 对象的 init 方法,安装样式的设置器和获取器
|
|
|
polyfilter.init();
|
|
|
ntentLoaded(window, function () {
|
|
|
polyfilter.process_stylesheets();
|
|
|
});
|
|
|
}
|
|
|
// 其他情况
|
|
|
else {
|
|
|
// 如果浏览器支持 addEventListener 方法(W3C 标准)
|
|
|
if (window.addEventListener) {
|
|
|
// 当 DOM 内容加载完成后,调用 polyfilter 对象的 process_stylesheets 方法处理样式表
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
polyfilter.process_stylesheets();
|
|
|
}, false);
|
|
|
}
|
|
|
// 如果浏览器支持 attachEvent 方法(Microsoft 标准)
|
|
|
else if (window.attachEvent) {
|
|
|
// 当页面加载完成后,调用 polyfilter 对象的 process_stylesheets 方法处理样式表
|
|
|
window.attachEvent('onload', function () {
|
|
|
polyfilter.process_stylesheets();
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 调用 polyfilter 对象的 init 方法,安装样式的设置器和获取器
|
|
|
polyfilter.init();
|