diff --git a/RManager注释.md b/RManager注释.md new file mode 100644 index 0000000..79f9d5f --- /dev/null +++ b/RManager注释.md @@ -0,0 +1,3051 @@ +/* +filter 包:Java Web 中 Filter 用于过滤请求,处理编码、权限验证、XSS 防护等。比如图中的 AdminFilter、XSSFilter,分别做权限和防攻击。 +javabean 包:存放实体类,封装数据,对应数据库表或业务数据。像 Admin、Manager 这些类,用于存储属性,遵循 JavaBean 规范,有 getter/setter 等。 +servlet 包:处理客户端请求,接收参数,调用业务逻辑,返回响应。比如 ManagerLogin 处理登录请求,Announcement 相关的处理公告操作。 +现在组织这些内容,分三个部分解释每个包的作用,确保清晰准确。 +*/ +/// +// * * * CharacterEncondingFilter.java +/** +* 字符编码过滤器,用于统一设置请求与响应的字符编码为UTF-8,解决文本乱码问题 + */ + public class CharacterEncodingFilter implements Filter { + + /** + * 过滤器初始化方法,由容器调用,用于获取过滤器配置参数等初始化操作 + * @param filterConfig 过滤器配置对象,可从中读取初始化参数 + * @throws ServletException 初始化过程中发生异常时抛出 + */ + public void init(FilterConfig filterConfig) throws ServletException { + } + + /** + * 执行过滤逻辑的核心方法,处理请求响应的编码设置 + * @param servletRequest 客户端发送的请求对象 + * @param servletResponse 服务器返回的响应对象 + * @param filterChain 过滤链,用于将请求响应传递给后续处理组件 + * @throws IOException 输入输出操作异常 + * @throws ServletException Servlet处理过程异常 + */ + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + // 设置请求编码为UTF-8,确保接收参数时字符编码统一 + servletRequest.setCharacterEncoding("UTF-8"); + // 设置响应编码为UTF-8,确保返回数据的字符编码统一 + servletResponse.setCharacterEncoding("UTF-8"); + // 将请求和响应传递给过滤链中的下一个组件(如其他过滤器或Servlet) + filterChain.doFilter(servletRequest, servletResponse); + } + + /** + * 过滤器销毁方法,由容器调用,用于释放过滤器占用的资源 + * 当前过滤器无需要释放的资源,方法体为空 + */ + public void destroy() { + } + } +// * * * ManagerFilter.java +package filter; +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +// * 图书管理员过滤类,用于拦截请求并校验用户是否为登录状态的图书管理员* 实现Filter接口,完成请求过滤逻辑 + public class ManagerFilter implements Filter { +// * 过滤器销毁方法,用于释放资源* 在过滤器生命周期结束时调用,此处暂无资源释放操作 + public void destroy() { + } + /** + * 核心过滤方法,处理请求过滤逻辑 + * @param request 客户端发送的请求对象 + * @param response 服务器返回的响应对象 + * @param chain 过滤器链,用于传递请求和响应 + * @throws IOException IO异常 + * @throws ServletException Servlet处理异常 + */ + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + // 将通用请求对象转换为Http请求对象 + HttpServletRequest req = (HttpServletRequest) request; + // 获取请求对应的HttpSession + HttpSession session = req.getSession(); + // 检查session是否存在,以及session中是否存在标识管理员登录的"manager"属性 + if (session == null || session.getAttribute("manager") == null) { + // 将通用响应对象转换为Http响应对象 + HttpServletResponse rep = (HttpServletResponse) response; + // 重定向到管理员登录页面,阻止未登录用户访问受保护资源 + rep.sendRedirect(req.getContextPath() + "/loginManager.html"); + return; // 终止后续过滤逻辑 + } + // 将请求和响应传递给过滤器链中的下一个组件(如其他过滤器或Servlet) + chain.doFilter(request, response); + } + +// * 过滤器初始化方法,用于获取配置参数等初始化操作* @param fConfig 过滤器配置对象* @throws ServletException Servlet初始化异常 +public void init(FilterConfig fConfig) throws ServletException { +} +} +// * XSS过滤器,用于过滤请求参数中的跨站脚本攻击代码(如 script、style 标签等),保护应用免受 XSS 攻击 + public class XSSFilter implements Filter { + + /** + * 过滤输入字符串中的 XSS 相关代码 + * @param htmlStr 待过滤的字符串 + * @return 过滤后的字符串,移除了 script、style、HTML 标签内容 + */ + public String filter(String htmlStr) { + if (htmlStr == null) { + return null; + } + // 定义匹配 script 标签的正则表达式,不区分大小写 + String regEx_script = "]*?>[\\s\\S]*?<\\/script>"; + // 定义匹配 style 标签的正则表达式,不区分大小写 + String regEx_style = "]*?>[\\s\\S]*?<\\/style>"; + // 定义匹配 HTML 标签的正则表达式,不区分大小写 + String regEx_html = "<[^>]+>"; + + // 编译 script 正则表达式为 Pattern 对象 + Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE); + Matcher m_script = p_script.matcher(htmlStr); + // 替换所有匹配的 script 标签内容为空,即过滤掉 script 标签 + htmlStr = m_script.replaceAll(""); + + // 编译 style 正则表达式为 Pattern 对象 + Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE); + Matcher m_style = p_style.matcher(htmlStr); + // 替换所有匹配的 style 标签内容为空,即过滤掉 style 标签 + htmlStr = m_style.replaceAll(""); + + // 编译 HTML 标签正则表达式为 Pattern 对象 + Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE); + Matcher m_html = p_html.matcher(htmlStr); + // 替换所有匹配的 HTML 标签内容为空,即过滤掉 HTML 标签 + htmlStr = m_html.replaceAll(""); + + return htmlStr.trim(); // 返回处理后去除首尾空白的字符串 + } +//自定义请求包装类,重写参数获取方法以实现 XSS 过滤 继承 HttpServletRequestWrapper,包装 HttpServletRequest 对象 + + class Request extends HttpServletRequestWrapper { + + public Request(HttpServletRequest request) { + super(request); + } +//重写获取多个参数值的方法,对每个参数值进行 XSS 过滤 ,@param name 参数名 ,@return 过滤后的参数值数组 + @Override + public String getParameter(String name) { + // 获取原始参数值并进行过滤 + return filter(super.getRequest().getParameter(name)); + } +// * * * XSSFilter.java +//重写获取多个参数值的方法,对每个参数值进行 XSS 过滤 ,@param name 参数名 ,@return 过滤后的参数值数组 + @Override + public String[] getParameterValues(String name) { + // 获取原始参数值数组 + String[] values = super.getRequest().getParameterValues(name); + // 遍历数组,对每个参数值进行过滤 + for (int i = 0; i < values.length; i++) { + values[i] = filter(values[i]); + } + return values; + } + } + + /** + * 执行过滤逻辑的核心方法 + * @param request 客户端请求对象 + * @param response 服务器响应对象 + * @param chain 过滤链,用于传递请求和响应 + * @throws IOException IO 异常 + * @throws ServletException Servlet 处理异常 + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + // 使用自定义的 Request 包装请求,实现参数过滤 + request = new Request((HttpServletRequest) request); + // 将过滤后的请求传递给过滤链后续组件 + chain.doFilter(request, response); + } +//过滤器销毁方法,用于释放资源(当前无资源释放操作) + @Override + public void destroy() { + } + } + +// * * * src/main/java/javabean/base.java +package javabean; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** +* 数据库操作基础类,封装数据库连接、查询、更新和资源释放的通用方法 +* 依赖DBConstants类获取数据库连接配置 + */ + public class Base { + // 数据库连接配置(从DBConstants类获取) + private static final String driver = DBConstants.driver; + private static final String url = DBConstants.url; + private static final String username = DBConstants.username; + private static final String password = DBConstants.password; + + /** + * 获取数据库连接 + * @return 数据库连接对象 + * @throws ClassNotFoundException 数据库驱动未找到异常 + */ + public static Connection getConnection() throws ClassNotFoundException { + Connection connection = null; + try { + // 加载数据库驱动 + Class.forName(driver); + // 建立数据库连接 + connection = (Connection) DriverManager.getConnection(url, username, password); + } catch (SQLException e) { + e.printStackTrace(); // 打印异常堆栈(实际项目建议日志记录) + } + return connection; + } + + /** + * 执行数据库查询操作 + * @param connection 数据库连接(可复用) + * @param preparedStatement 预编译语句(可复用) + * @param resultSet 结果集(可复用) + * @param sql SQL语句 + * @param params 参数数组(用于预编译语句的占位符) + * @return 查询结果集 + * @throws SQLException SQL执行异常 + */ + public static ResultSet executequery(Connection connection, PreparedStatement preparedStatement, + ResultSet resultSet, String sql, Object[] params) throws SQLException { + // 如果预编译语句为空,则创建新实例 + if (preparedStatement == null) { + preparedStatement = (PreparedStatement) connection.prepareStatement(sql); + } + // 设置预编译语句参数 + for (int i = 0; params != null && i < params.length; i++) { + preparedStatement.setObject(i + 1, params[i]); + } + // 执行查询并返回结果集 + resultSet = preparedStatement.executeQuery(); + return resultSet; + } + + /** + * 执行数据库更新操作(INSERT/UPDATE/DELETE) + * @param connection 数据库连接(可复用) + * @param preparedStatement 预编译语句(可复用) + * @param sql SQL语句 + * @param params 参数数组(用于预编译语句的占位符) + * @return 受影响的行数 + * @throws SQLException SQL执行异常 + */ + public static int executeUpdate(Connection connection, PreparedStatement preparedStatement, String sql, + Object[] params) throws SQLException { + // 如果预编译语句为空,则创建新实例 + if (preparedStatement == null) { + preparedStatement = (PreparedStatement) connection.prepareStatement(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 预编译语句(可选) + * @param resultSet 结果集(可选) + * @return 资源释放成功标志 + * @throws SQLException 资源释放异常 + */ + public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) + throws SQLException { + boolean flag = true; + // 按顺序关闭资源:结果集 → 预编译语句 → 连接 + if (resultSet != null) { + try { + resultSet.close(); + resultSet = null; + } catch (SQLException e) { + e.printStackTrace(); + flag = false; + } + } + if (preparedStatement != null) { + try { + preparedStatement.close(); + preparedStatement = null; + } catch (SQLException e) { + e.printStackTrace(); + flag = false; + } + } + if (connection != null) { + try { + connection.close(); + connection = null; + } catch (SQLException e) { + e.printStackTrace(); + flag = false; + } + } + return flag; + } + } +// * * * src/main/java/javabean/DBConstants.java +package javabean; +/** +* 数据库连接配置类,存储数据库连接所需的常量参数 +* 注意:实际项目中应避免硬编码密码,建议使用配置文件或环境变量 + */ + public class DBConstants { + // MySQL JDBC驱动类(适用于MySQL Connector/J 8.0+版本) + public static final String driver = "com.mysql.cj.jdbc.Driver"; + + // 数据库连接URL + // 格式:jdbc:mysql://<主机>:<端口>/<数据库名>?参数 + // 示例说明: + // - localhost:3306:本地MySQL服务,默认端口 + // - 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"; + + // 数据库用户名(通常为root或具有适当权限的用户) + public static final String username = "root"; + + // 数据库密码(注意:硬编码密码存在安全风险,建议使用配置文件或环境变量) + public static final String password = "123456"; + } + // * * * src/main/java/javabean/JDBCBean.java + package javabean; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +/** +* 数据库操作工具类,封装基本的JDBC操作(存在安全风险和性能问题,建议改进) +* 注意:直接使用Statement存在SQL注入风险,建议改用PreparedStatement + */ + public class JDBCBean { + // 数据库连接配置(从DBConstants类获取) + private static final String driver = DBConstants.driver; + private static final String url = DBConstants.url; + private static final String username = DBConstants.username; + private static final String password = DBConstants.password; + + // 数据库连接和操作对象 + private Connection conn = null; + private Statement stmt = null; + + /** + * 构造方法:初始化数据库连接和Statement对象 + * 注意:直接抛出异常到调用者,避免在构造方法中吞掉异常 + * 潜在问题:每次实例化都会创建新连接,未使用连接池,影响性能 + */ + public JDBCBean() { + try { + Class.forName(driver); // 加载数据库驱动 + conn = DriverManager.getConnection(url, username, password); // 建立连接 + stmt = conn.createStatement(); // 创建Statement对象(存在SQL注入风险) + System.out.println("成功与数据库建立连接!"); + } catch (ClassNotFoundException | SQLException e) { + System.out.println("无法与数据库建立连接!"); + e.printStackTrace(); // 打印异常堆栈(生产环境应使用日志记录) + } + } + + /** + * 执行数据库更新操作(INSERT/UPDATE/DELETE) + * @param s SQL语句(存在SQL注入风险) + * @return 受影响的行数 + */ + public int executeUpdate(String s) { + int result = 0; + try { + System.out.println("执行SQL:" + s); // 调试输出,生产环境应移除 + result = stmt.executeUpdate(s); + } catch (SQLException e) { + System.out.println("执行更新错误!"); + e.printStackTrace(); + } + return result; + } + + /** + * 执行数据库查询操作 + * @param s SQL语句(存在SQL注入风险) + * @return 查询结果集(需要手动关闭) + */ + public ResultSet executeQuery(String s) { + ResultSet rs = null; + try { + rs = stmt.executeQuery(s); + } catch (SQLException e) { + System.out.println("执行查询错误!" + e.getMessage()); + e.printStackTrace(); + } + return rs; + } + + /** + * 关闭数据库资源(Statement和Connection) + * 注意:未正确处理异常,可能导致资源泄漏 + * 建议:使用try-with-resources或在finally块中调用 + */ + public void close() { + try { + if (stmt != null) stmt.close(); + if (conn != null) conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } +// * * * src/main/java/javabean/Common.java +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; + +/** +* 通用数据库操作工具类,提供表行数统计和图书馆信息映射等功能 + */ + public class Common { + + /** + * 获取指定表的总记录数 + * @param table 表名(不能为空) + * @return 记录总数(若表不存在或查询失败返回0) + * @throws ClassNotFoundException 数据库驱动未找到异常 + * @throws SQLException SQL执行异常 + */ + public static int getCount(String table) throws SQLException, ClassNotFoundException { + if (table == null || table.equals("")) { + return 0; // 表名为空直接返回0 + } + + Connection connection = null; + PreparedStatement pstmt = null; + ResultSet resultSet = null; + try { + connection = Base.getConnection(); // 获取数据库连接 + // 构建查询总行数的SQL语句 + pstmt = connection.prepareStatement("SELECT COUNT(*) AS count FROM " + table); + resultSet = pstmt.executeQuery(); // 执行查询 + resultSet.next(); // 移动到结果集第一条记录 + return resultSet.getInt("count"); // 返回总记录数 + } catch (SQLException e) { + e.printStackTrace(); // 打印异常堆栈(实际项目建议日志记录) + return 0; // 查询失败返回0 + } finally { + // 释放数据库资源 + Base.closeResource(connection, pstmt, resultSet); + } + } + + /** + * 获取所有图书馆的ID-名称映射(按ID升序排列) + * @return TreeMap<图书馆ID, 图书馆名称>(若查询失败返回null) + * @throws SQLException SQL执行异常 + */ + public static TreeMap getLibraryMap() throws SQLException { + Connection connection = null; + PreparedStatement libraryPstmt = null; + ResultSet librarySet = null; + String librarySql = "SELECT id, name FROM library"; // 查询图书馆的SQL语句 + + TreeMap map = new TreeMap<>(); // 使用TreeMap自动按键(ID)排序 + + try { + connection = Base.getConnection(); // 获取数据库连接 + libraryPstmt = connection.prepareStatement(librarySql); // 创建预编译语句 + librarySet = libraryPstmt.executeQuery(); // 执行查询 + + // 遍历结果集,填充TreeMap + while (librarySet.next()) { + String id = librarySet.getString("id"); + String name = librarySet.getString("name"); + map.put(id, name); // 键为ID,值为名称 + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; // 驱动未找到返回null + } catch (SQLException e) { + e.printStackTrace(); + return null; // SQL执行失败返回null + } finally { + // 释放数据库资源 + Base.closeResource(connection, libraryPstmt, librarySet); + } + return map; + } + + /** + * 测试方法(实际项目建议删除) + * @param args 命令行参数 + * @throws SQLException SQL执行异常 + */ + public static void main(String[] args) throws SQLException { + System.out.println(Common.getLibraryMap()); // 打印图书馆映射 + } + } +// * * * src/main/java/javabean/CompareDate.java + package javabean; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** +* 日期比较工具类,提供计算两个日期字符串时间差的功能 + */ + public class CompareDate { + + /** + * 计算两个日期字符串之间的天数差(结束日期 - 开始日期) + * @param Str1 开始日期字符串(格式:yyyy-MM-dd HH:mm:ss) + * @param Str2 结束日期字符串(格式:yyyy-MM-dd HH:mm:ss) + * @return 相差的天数(可能为负数,表示结束日期早于开始日期) + * @throws ParseException 日期格式不正确时抛出(当前方法未处理,直接打印堆栈) + * @implNote 使用SimpleDateFormat进行日期解析,存在线程不安全问题 + * @implNote 时间差计算为毫秒差除以一天的毫秒数(24*60*60*1000),结果为整数天数 + */ + public static long show(String Str1, String Str2) { + long between = 0; + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + Date date1 = format.parse(Str1); // 解析开始日期 + Date date2 = format.parse(Str2); // 解析结束日期 + between = date2.getTime() - date1.getTime(); // 计算时间差(毫秒) + } catch (ParseException e) { + e.printStackTrace(); // 打印异常堆栈(实际项目应处理异常) + } + // 转换为天数(注意:直接除以一天的毫秒数可能导致精度丢失) + long days = between / (24 * 60 * 60 * 1000); + return days; + } + + // 示例用法 + public static void main(String[] args) { + long days = CompareDate.show("2023-01-01 00:00:00", "2023-01-03 23:59:59"); + System.out.println("相差天数:" + days); // 输出:2 + } + } +// * * * Manager.java +package javabean; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** +* 管理员业务逻辑处理类,封装管理员登录验证功能 + */ + public class Manager { + + /** + * 管理员登录验证方法 + * @param user 管理员账号 + * @param psw 管理员密码 + * @return 验证结果:"1"表示成功,其他字符串表示失败原因 + * @throws ClassNotFoundException 数据库驱动未找到异常 + * @throws SQLException 数据库操作异常 + */ + @SuppressWarnings("null") // 抑制空指针警告(resultSet在finally中已关闭) + 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 connection = null; + PreparedStatement pstmt = null; + ResultSet resultSet = null; + String sql = "select * from manager where ACCOUNT=? and PASSWORD=?"; + + try { + connection = Base.getConnection(); // 获取数据库连接 + pstmt = connection.prepareStatement(sql); // 预编译SQL + pstmt.setString(1, user); // 绑定账号参数 + pstmt.setString(2, psw); // 绑定密码参数 + resultSet = pstmt.executeQuery(); // 执行查询 + + if (resultSet.next()) { // 若存在匹配记录 + return "1"; // 返回成功标识 + } + return "账号或密码错误"; // 查询无结果时返回错误信息 + + } finally { + // 释放数据库资源 + Base.closeResource(connection, pstmt, resultSet); + } + } + } +// * * * java/servlet/announcement.java +package servlet.manager; +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 javabean.Util; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +/** +* 公告管理Servlet,处理公告查询请求 +* 映射路径:/manager/announcement +* 仅响应GET请求,返回公告列表的JSON数据 + */ + @WebServlet("/manager/announcement") + public class Announcement extends HttpServlet { + + /** + * 处理GET请求,查询公告列表并返回JSON数据 + * @param req HTTP请求对象 + * @param resp HTTP响应对象 + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 设置响应格式为JSON,字符集UTF-8 + resp.setContentType("application/json; charset=utf8"); + + // 数据库操作变量 + Connection connection = null; + PreparedStatement pstmt = null; + String sql = ""; + ResultSet resultSet = null; + + // 响应数据 + int code = 1; // 状态码:1=失败,0=成功 + String msg = "无数据"; // 状态描述 + JSONObject jsonObject = new JSONObject(); // 单条公告JSON对象 + JSONArray jsonArray = new JSONArray(); // 公告列表JSON数组 + + try { + // 获取数据库连接 + connection = Base.getConnection(); + // 查询所有公告的SQL语句 + sql = "select * from announcement"; + pstmt = connection.prepareStatement(sql); + resultSet = pstmt.executeQuery(); + + // 遍历结果集,封装为JSON格式 + while (resultSet.next()) { + jsonObject.put("id", resultSet.getString("id")); // 公告ID + jsonObject.put("title", resultSet.getString("title")); // 公告标题 + jsonObject.put("detail", resultSet.getString("detail")); // 公告详情 + jsonObject.put("publish_date", resultSet.getString("publish_date")); // 发布日期 + jsonArray.add(jsonObject); // 添加到公告列表 + } + + // 根据查询结果设置响应状态 + if (!jsonArray.isEmpty()) { + code = 0; + msg = "查询成功"; + } else { + msg = "数据为空"; + } + + } catch (ClassNotFoundException e) { + msg = "数据库驱动未找到"; + } catch (SQLException e) { + msg = "SQL执行错误"; + } finally { + // 释放数据库资源 + try { + Base.closeResource(connection, pstmt, resultSet); + } catch (SQLException e) { + msg = "资源释放失败"; + } + } + + // 生成最终响应JSON + PrintWriter out = resp.getWriter(); + out.print(Util.jsonResponse(code, msg, jsonArray.toString())); + } + } +// * * * java/servlet/announcementAdd.java +package servlet.manager; +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 javabean.DateTime; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +/** +* 公告添加Servlet,处理公告发布请求 +* 映射路径:/manager/announcementAdd +* 仅响应POST请求,接收公告标题、内容并保存到数据库 + */ + @WebServlet("/manager/announcementAdd") + public class AnnouncementAdd extends HttpServlet { + + /** + * 处理POST请求,接收公告信息并插入数据库 + * @param req HTTP请求对象(包含公告标题、内容参数) + * @param resp HTTP响应对象(返回操作结果JSON) + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 设置响应格式为JSON,字符集UTF-8 + resp.setContentType("application/json; charset=utf8"); + + // 接收客户端提交的参数 + String id = req.getParameter("id"); // 未使用的参数(可能为测试保留) + String tit = req.getParameter("title"); // 公告标题 + String det = req.getParameter("detail"); // 公告内容 + DateTime date = new DateTime(); // 获取当前时间 + String time = date.show(); // 格式化时间字符串 + + // 数据库操作变量 + Connection connection = null; + PreparedStatement pstmt = null; + ResultSet resultSet = null; + int result = 0; // 数据库操作影响的行数 + int count = 0; // 未使用的计数器(可能为测试保留) + + // 响应数据 + int code = 1; // 状态码:1=失败,0=成功 + String msg = ""; // 状态描述 + JSONArray jsonArray = new JSONArray(); // 未使用的JSON数组(可能为测试保留) + JSONObject json = new JSONObject(); // 响应结果JSON对象 + + // SQL语句:插入公告信息(注意:id字段未包含,由数据库自增) + String sql = "insert into announcement(title, detail, publish_date) values(?,?,?)"; + System.out.println(sql); // 控制台打印SQL语句(生产环境建议移除) + + PrintWriter out = resp.getWriter(); // 获取响应输出流 + + try { + // 获取数据库连接 + connection = Base.getConnection(); + // 预编译SQL语句 + pstmt = connection.prepareStatement(sql); + // 绑定参数:标题、内容、发布时间 + pstmt.setString(1, tit); + pstmt.setString(2, det); + pstmt.setString(3, time); + // 执行插入操作 + result = pstmt.executeUpdate(); + + } catch (SQLException e) { + // 捕获SQL异常(未处理具体错误信息,建议添加日志) + } catch (ClassNotFoundException e) { + e.printStackTrace(); // 打印驱动未找到异常堆栈 + } finally { + // 释放数据库资源(结果集为null,无需关闭) + try { + Base.closeResource(connection, pstmt, null); + } catch (SQLException e) { + e.printStackTrace(); // 打印资源释放异常堆栈 + } + } + + // 根据操作结果生成响应JSON + if (result == 1) { + json.put("code", "0"); + json.put("msg", "success"); + } else { + json.put("code", "1"); + json.put("msg", "error"); + } + out.write(json.toString()); // 输出响应结果 + } + } + +// * * * java/servlet/announcementDel.java +package servlet.manager; +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 javabean.Util; + +/** +* 公告删除Servlet,处理公告删除请求 +* 映射路径:/manager/announcementDel +* 仅响应GET请求,根据公告ID执行删除操作 + */ + @WebServlet("/manager/announcementDel") + public class AnnouncementDel extends HttpServlet { + + /** + * 处理GET请求,根据ID删除公告并返回JSON响应 + * @param req HTTP请求对象(包含公告ID参数id) + * @param resp HTTP响应对象(返回删除结果JSON) + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 获取请求参数:公告ID + String id = req.getParameter("id"); + + // 数据库操作变量 + String sql = ""; // SQL语句 + Connection connection = null; // 数据库连接 + PreparedStatement pstmt = null; // 预编译语句 + ResultSet resultSet = null; // 结果集(未使用) + int result = 0; // 数据库操作影响的行数 + + // 响应数据 + int code = 1; // 状态码:1=失败,0=成功 + String msg = ""; // 状态描述 + PrintWriter out = resp.getWriter(); // 响应输出流 + + try { + // 获取数据库连接 + connection = Base.getConnection(); + // 预编译删除SQL,使用占位符?防止SQL注入 + sql = "delete from announcement where id=?"; + pstmt = connection.prepareStatement(sql); + // 绑定参数:公告ID + pstmt.setString(1, id); + // 执行删除操作 + result = pstmt.executeUpdate(); + + // 根据影响的行数判断操作结果 + if (result == 1) { + code = 0; + msg = "删除成功"; + } else { + msg = "删除失败(ID不存在或操作异常)"; + } + + } catch (ClassNotFoundException e) { + msg = "数据库驱动未找到"; + } catch (SQLException e) { + msg = "SQL执行错误:" + e.getMessage(); // 建议记录详细错误日志 + } finally { + // 释放数据库资源 + try { + Base.closeResource(connection, pstmt, resultSet); + } catch (SQLException e) { + e.printStackTrace(); // 打印资源释放异常堆栈 + } + } + + // 生成JSON响应:状态码、消息、空数据 + out.print(Util.jsonResponse(code, msg, null)); + } + } + +// * * * java/servlet/announcementEdit.java +package servlet.manager; +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 javabean.Util; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +/** +* 公告编辑Servlet,处理公告内容修改请求 +* 映射路径:/manager/announcementEdit +* 仅响应POST请求,接收公告ID、新标题和内容并更新数据库 + */ + @WebServlet("/manager/announcementEdit") + public class AnnouncementEdit extends HttpServlet { + + /** + * 处理POST请求,执行公告内容修改并返回JSON响应 + * @param req HTTP请求对象(包含公告ID、新标题和内容参数) + * @param resp HTTP响应对象(返回操作结果JSON) + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 设置响应格式为JSON,字符集UTF-8 + resp.setContentType("application/json; charset=utf8"); + + // 接收客户端提交的参数 + String id = req.getParameter("id"); // 公告ID(未校验非空) + String tit = req.getParameter("title"); // 新公告标题 + String det = req.getParameter("detail"); // 新公告内容 + + // 数据库操作变量 + String sql = ""; // SQL语句 + Connection connection = null; // 数据库连接 + PreparedStatement pstmt = null; // 预编译语句 + ResultSet resultSet = null; // 结果集(未使用) + int result = 0; // 数据库操作影响的行数 + + // 响应数据 + int code = 1; // 状态码:1=失败,0=成功 + String msg = ""; // 状态描述 + PrintWriter out = resp.getWriter(); // 响应输出流 + JSONArray jsonArray = new JSONArray(); // 未使用的JSON数组(建议删除) + JSONObject jsonObject = new JSONObject(); // 未使用的JSON对象(建议删除) + + // 参数校验:标题和内容不能为空 + if (tit == null || tit.equals("") || det == null || det.equals("")) { + msg = "参数不能为空"; + out.print(Util.jsonResponse(code, msg, null)); + return; // 终止后续处理 + } + + try { + // 获取数据库连接 + connection = Base.getConnection(); + // 预编译更新SQL,使用占位符?防止SQL注入 + sql = "update announcement set title=?, detail=? where id=?"; + pstmt = connection.prepareStatement(sql); + // 绑定参数:新标题、新内容、公告ID + pstmt.setString(1, tit); + pstmt.setString(2, det); + pstmt.setString(3, id); + // 执行更新操作 + result = pstmt.executeUpdate(); + + // 根据影响的行数判断操作结果 + if (result == 1) { + code = 0; + msg = "修改成功"; + } else { + msg = "修改失败(ID不存在或操作异常)"; + } + + } catch (ClassNotFoundException e) { + msg = "数据库驱动未找到"; + } catch (SQLException e) { + msg = "SQL执行错误:" + e.getMessage(); // 建议记录详细错误日志 + } finally { + // 释放数据库资源 + try { + Base.closeResource(connection, pstmt, resultSet); + } catch (SQLException e) { + e.printStackTrace(); // 打印资源释放异常堆栈 + } + } + + // 生成JSON响应:状态码、消息、空数据 + out.print(Util.jsonResponse(code, msg, null)); + } + } + +// * * * java/servlet/BorrowTable.java +package servlet.manager; + +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,处理分页查询和条件过滤请求 +* 映射路径:/manager/borrowTable +* 仅响应GET请求,返回符合条件的借阅记录列表(JSON格式) + */ + @WebServlet("/manager/borrowTable") + public class BorrowTable extends HttpServlet { + + /** + * 处理GET请求,执行分页查询并返回JSON数据 + * @param req HTTP请求对象(包含分页参数和过滤条件) + * @param resp HTTP响应对象(返回查询结果JSON) + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 设置响应格式为JSON,字符集UTF-8 + resp.setContentType("application/json; charset=utf8"); + + // 接收客户端参数 + String limit = req.getParameter("limit"); // 每页显示数量 + String page = req.getParameter("page"); // 当前页码 + String condition = req.getParameter("condition"); // 过滤字段(如card_id) + String conditionValue = req.getParameter("conditionValue"); // 过滤值 + + // 初始化查询条件 + String where = ""; // 无限制条件 + if (page == null) page = "1"; // 默认页码1 + if (limit == null) limit = "10"; // 默认每页10条 + + // 数据库操作变量 + Connection connection = null; + PreparedStatement pstmt = null; // 数据查询语句 + PreparedStatement countPstmt = null; // 总数查询语句 + ResultSet resultSet = null; + ResultSet countSet = null; + String sql = ""; + String countSql = ""; + + // 响应数据 + int code = 1; // 状态码:1=失败,0=成功 + String msg = "无数据"; // 状态描述 + int count = 0; // 总记录数 + JSONObject jsonData = new JSONObject(); // 单条记录JSON对象 + JSONArray jsonArray = new JSONArray(); // 记录列表JSON数组 + JSONObject jsonResult = new JSONObject(); // 最终响应JSON + + try { + // 获取数据库连接 + connection = Base.getConnection(); + + // 构建基础查询SQL(过滤manager_id不为null的记录) + sql = "select * from borrow_books where manager_id is not null"; + // 拼接条件查询(注意:直接拼接字符串存在SQL注入风险) + if (condition != null && conditionValue != null + && !condition.equals("") && !conditionValue.equals("")) { + where = " and " + condition + " like '%" + conditionValue + "%' "; + sql += where; + } + // 拼接分页参数(使用预编译占位符) + sql += " limit ?,?"; + System.out.println("查询SQL:" + sql); // 调试用,生产环境建议移除 + + // 执行数据查询 + pstmt = connection.prepareStatement(sql); + // 计算分页偏移量:(当前页-1)*每页数量 + pstmt.setInt(1, (Integer.parseInt(page) - 1) * Integer.parseInt(limit)); + pstmt.setInt(2, Integer.parseInt(limit)); + resultSet = pstmt.executeQuery(); + + // 封装查询结果为JSON + while (resultSet.next()) { + jsonData.put("id", resultSet.getString("id")); // 记录ID + jsonData.put("card_id", resultSet.getString("card_id")); // 读者卡号 + jsonData.put("book_id", resultSet.getString("book_id")); // 图书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")); // 管理员ID + jsonArray.add(jsonData); // 添加到记录列表 + } + + // 执行总记录数查询 + countSql = "select count(*) as count from borrow_books where manager_id is not null" + where; + countPstmt = connection.prepareStatement(countSql); + countSet = countPstmt.executeQuery(); + if (countSet.next()) { + count = countSet.getInt("count"); // 获取总记录数 + } + + // 设置响应状态 + if (!jsonArray.isEmpty()) { + code = 0; + msg = "查询成功"; + } + + } catch (ClassNotFoundException e) { + msg = "数据库驱动未找到"; + } catch (SQLException e) { + msg = "SQL执行错误:" + e.getMessage(); + } finally { + // 分批次释放资源 + try { + 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()); // 转换为JSON数组 + + // 输出响应 + PrintWriter out = resp.getWriter(); + out.print(jsonResult.toString()); + } + } + +// * * * java/servlet/ManagerLogin.java +package servlet.manager; + +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.SQLException; +import java.util.HashMap; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import javabean.Manager; +import net.sf.json.JSONObject; + +/** +* 管理员登录Servlet,处理管理员登录请求 +* 映射路径:/managerLogin +* 仅响应POST请求,验证账号密码并返回登录结果 + */ + @WebServlet("/managerLogin") + public class ManagerLogin extends HttpServlet { + + /** + * 处理GET请求(未使用,返回简单提示) + * @param request HTTP请求对象 + * @param response HTTP响应对象 + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.getWriter().append("Served at: ").append(request.getContextPath()); + } + + /** + * 处理POST请求,执行管理员登录验证 + * @param request HTTP请求对象(包含user和psw参数) + * @param response HTTP响应对象(返回JSON格式的登录结果) + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // 设置响应格式为JSON,字符集UTF-8 + response.setContentType("application/json; charset=utf8"); + PrintWriter out = response.getWriter(); + + // 获取客户端提交的账号和密码 + String user = request.getParameter("user"); // 管理员账号 + String psw = request.getParameter("psw"); // 管理员密码 + + // 响应数据容器 + HashMap hashMap = new HashMap<>(); + + // 调用业务逻辑层验证登录 + Manager manager = new Manager(); + String result = null; + try { + result = manager.login(user, psw); // 调用Manager类的登录方法 + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); // 打印数据库相关异常堆栈(生产环境建议日志记录) + } + + // 根据验证结果生成响应 + if (result.equals("1")) { // 登录成功 + HttpSession session = request.getSession(); + session.setAttribute("manager", user); // 记录登录用户 + session.setAttribute("manager_first", "1"); // 标记首次登录状态 + hashMap.put("code", 0); + hashMap.put("msg", "登录成功"); + // 返回跳转URL(前端根据此字段进行页面跳转) + hashMap.put("url", request.getContextPath() + "/manager/01nav.jsp"); + } else { // 登录失败 + hashMap.put("code", 1); + hashMap.put("msg", result); // 错误信息直接来自业务层 + } + + // 将响应数据转换为JSON并输出 + JSONObject json = JSONObject.fromObject(hashMap); + out.write(json.toString()); + } + } +// * * * java/servlet/Quit.java +package servlet.manager; +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,处理管理员注销请求 +* 映射路径:/manager/quit +* 仅响应GET请求,销毁用户会话并重定向到登录页面 + */ + @WebServlet("/manager/quit") + public class Quit extends HttpServlet { + private static final long serialVersionUID = 1L; + + /** + * 处理GET请求,执行管理员退出逻辑 + * @param req HTTP请求对象 + * @param resp HTTP响应对象 + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 获取当前会话 + HttpSession session = req.getSession(); + + // 检查会话中是否存在管理员登录标识 + if (session.getAttribute("manager") != null) { + // 移除登录状态,终止会话 + session.removeAttribute("manager"); + } + + // 重定向到管理员登录页面 + resp.sendRedirect(req.getContextPath() + "/loginManager.html"); + } + } +// * * * java/servlet/ReturnTable.java +package servlet.manager; +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,处理分页查询和条件过滤请求 +* 映射路径:/manager/returnTable +* 仅响应GET请求,返回未处理的借阅记录列表(JSON格式) + */ + @WebServlet("/manager/returnTable") + public class ReturnTable extends HttpServlet { + + /** + * 处理GET请求,执行分页查询并返回JSON数据 + * @param req HTTP请求对象(包含分页参数和过滤条件) + * @param resp HTTP响应对象(返回查询结果JSON) + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 设置响应格式为JSON,字符集UTF-8 + resp.setContentType("application/json; charset=utf8"); + + // 接收客户端参数 + String limit = req.getParameter("limit"); // 每页显示数量 + String page = req.getParameter("page"); // 当前页码 + String condition = req.getParameter("condition"); // 过滤字段(如card_id) + String conditionValue = req.getParameter("conditionValue"); // 过滤值 + + // 初始化查询条件 + String where = ""; // 无限制条件 + if (page == null) page = "1"; // 默认页码1 + if (limit == null) limit = "10"; // 默认每页10条 + + // 数据库操作变量 + Connection connection = null; + PreparedStatement pstmt = null; // 数据查询语句 + PreparedStatement countPstmt = null; // 总数查询语句 + ResultSet resultSet = null; + ResultSet countSet = null; + String sql = ""; + String countSql = ""; + + // 响应数据 + int code = 1; // 状态码:1=失败,0=成功 + String msg = "无数据"; // 状态描述 + int count = 0; // 总记录数 + JSONObject jsonData = new JSONObject(); // 单条记录JSON对象 + JSONArray jsonArray = new JSONArray(); // 记录列表JSON数组 + JSONObject jsonResult = new JSONObject(); // 最终响应JSON + + try { + // 获取数据库连接 + connection = Base.getConnection(); + + // 构建基础查询SQL(过滤manager_id为null的记录) + sql = "select * from borrow_books where manager_id is null"; + // 拼接条件查询(注意:直接拼接字符串存在SQL注入风险) + if (condition != null && conditionValue != null + && !condition.equals("") && !conditionValue.equals("")) { + where = " and " + condition + " like '%" + conditionValue + "%' "; + sql += where; + } + // 拼接分页参数(使用预编译占位符) + sql += " limit ?,?"; + System.out.println("查询SQL:" + sql); // 调试用,生产环境建议移除 + + // 执行数据查询 + pstmt = connection.prepareStatement(sql); + // 计算分页偏移量:(当前页-1)*每页数量 + pstmt.setInt(1, (Integer.parseInt(page) - 1) * Integer.parseInt(limit)); + pstmt.setInt(2, Integer.parseInt(limit)); + resultSet = pstmt.executeQuery(); + + // 封装查询结果为JSON + while (resultSet.next()) { + jsonData.put("id", resultSet.getString("id")); // 记录ID + jsonData.put("card_id", resultSet.getString("card_id")); // 读者卡号 + jsonData.put("book_id", resultSet.getString("book_id")); // 图书ID + jsonData.put("borrow_date", resultSet.getString("borrow_date")); // 借阅日期 + jsonData.put("end_date", resultSet.getString("end_date")); // 应还日期 + jsonArray.add(jsonData); // 添加到记录列表 + } + + // 执行总记录数查询 + countSql = "select count(*) as count from borrow_books where manager_id is null" + where; + countPstmt = connection.prepareStatement(countSql); + countSet = countPstmt.executeQuery(); + if (countSet.next()) { + count = countSet.getInt("count"); // 获取总记录数 + } + + // 设置响应状态 + if (!jsonArray.isEmpty()) { + code = 0; + msg = "查询成功"; + } + + } catch (ClassNotFoundException e) { + msg = "数据库驱动未找到"; + } catch (SQLException e) { + msg = "SQL执行错误:" + e.getMessage(); + } finally { + // 分批次释放资源 + try { + 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()); // 转换为JSON数组 + + // 输出响应 + PrintWriter out = resp.getWriter(); + out.print(jsonResult.toString()); + } + + /** + * 处理POST请求(未使用) + * @param request HTTP请求对象 + * @param response HTTP响应对象 + * @throws ServletException Servlet处理异常 + * @throws IOException IO异常 + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + // 未实现POST逻辑 + } + } + +// * * * 前端页面 jsp + +// * * * 01nav.jsp + + +
+ + +
+ + + + + + + +
+ + + + + +
+ +
+ + + +
+ + + + + +// * * 02borrow.jsp + + + 借阅图书 + + + + + + + + + +
+

借阅图书

+
+ + +
+ +
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+
+ + + +
+ + +// * * * 03borrowSus.jsp + + + 借阅图书处理 + + + + + <% + // 获取表单提交参数 + String user = request.getParameter("userid"); // 借阅证号 + String book = request.getParameter("bookid"); // 图书编号 + String date1 = request.getParameter("date1"); // 借阅日期 + + // 查询借阅证信息 + String sql1 = "select * from borrow_card where ID =" + user; + ResultSet rs1 = borrow.executeQuery(sql1); + + // 管理员登录验证 + if (session.getAttribute("manager") != null) { + if (rs1.next()) { + // 获取借阅证状态和规则ID + String rule = rs1.getString("rule_id"); + int cardstatus = Integer.parseInt(rs1.getString("STATUS")); + + // 查询借阅规则 + String sql4 = "select * from rules where id = " + rule; + ResultSet rs4 = borrow.executeQuery(sql4); + int n = 0; // 借阅天数 + String library = ""; // 可借阅图书馆 + String[] libraryArray = {}; + int num = 0; // 最大借阅数量 + + while (rs4.next()) { + n = rs4.getInt("limit_day"); + library = rs4.getString("borrow_library"); + libraryArray = library.split("、"); + num = rs4.getInt("borrow_num"); + } + + // 计算应还日期 + EndTime endtime = new EndTime(); + String end = endtime.show(n); + + // 借阅证状态检查 + if (cardstatus != 0) { + // 查询图书信息 + String sql2 = "select * from books where ID =" + book; + ResultSet rs2 = borrow.executeQuery(sql2); + + if (rs2.next()) { + int status = Integer.parseInt(rs2.getString("STATUS")); // 图书状态 + String lib = Integer.toString(rs2.getInt("library_id")); // 图书所在图书馆 + + // 检查图书是否在可借阅图书馆列表 + boolean validLibrary = false; + for (int z = 0; z < libraryArray.length; z++) { + if (libraryArray[z].equals(lib)) { + validLibrary = true; + + // 查询当前用户未处理的借阅数量 + String countSql = "select count(*) as count from borrow_books where manager_id is null and card_id =" + user; + ResultSet rsSql = borrow.executeQuery(countSql); + int count = 0; + while (rsSql.next()) { + count = rsSql.getInt("count"); + } + + // 检查借阅数量限制 + if (count < num) { + if (status == 1) { // 图书可用 + // 执行借阅操作 + String sql = "insert borrow_books(CARD_ID,BOOK_ID,BORROW_DATE,END_DATE) values('" + user + "','" + book + "','" + date1 + "','" + end + "')"; + try { + int i = borrow.executeUpdate(sql); + if (i == 1) { + // 更新图书状态为已借出 + borrow.executeUpdate("update books set STATUS=0 where ID=" + book); + %> + + <% + } else { + %> + + <% + } + } catch (Exception e) { + %> + + <% + } + } else { + %> + + <% + } + } else { + %> + + <% + } + break; + } + } + + // 图书馆权限检查失败 + if (!validLibrary) { + %> + + <% + } + } else { + %> + + <% + } + } else { + %> + + <% + } + } else { + %> + + <% + } + } else { + %> + + <% + } + %> + +// * * * 04judge.jsp + + + 查询图书是否逾期 + + + + + + + + + +
+

查询图书是否逾期

+
+ + +
+ +
+ +
+ +
+ +
+
+ + +
+ +
+
+ + + +
+ + +// * * * 04judgeSus.jsp + + + 图书逾期查询处理 + + + + + <% + // 获取表单提交的图书编号 + String book = request.getParameter("bookid"); + session.setAttribute("book", book); // 将会话保存到session + + // 管理员登录验证 + if (session.getAttribute("manager") != null) { + DateTime date = new DateTime(); + String now = date.show(); // 获取当前时间 + String bookid = request.getParameter("bookid"); + + // 查询该图书的借阅记录 + String sql = "select * from borrow_books where book_id = " + bookid; + ResultSet rs = judge.executeQuery(sql); + String end = ""; // 应还日期 + String ret = ""; // 归还日期 + String card = ""; // 借阅证号 + + while (rs.next()) { + end = rs.getString("end_date"); + ret = rs.getString("return_date"); + card = rs.getString("card_id"); + } + + if (ret == null) { // 图书未归还 + // 计算逾期天数(now与end的时间差) + long n = CompareDate.show(now, end); + session.setAttribute("days", n); // 保存逾期天数 + + // 查询借阅证规则 + String sql1 = "select * from borrow_card where id = " + card; + ResultSet rs1 = judge.executeQuery(sql1); + String rule = ""; + while (rs1.next()) { + rule = rs1.getString("rule_id"); + } + + // 查询逾期费用规则 + String sql2 = "select * from rules where id = " + rule; + ResultSet rs2 = judge.executeQuery(sql2); + String fee = ""; + while (rs2.next()) { + fee = rs2.getString("overtime_fee"); + } + session.setAttribute("fee", fee); // 保存逾期费用 + + // 跳转到图书归还页面 + %> + + <% + } else { // 图书已归还 + %> + + <% + } + } else { // 未登录处理 + %> + + <% + } + %> + +// * * * 04return.jsp + + + 归还图书 + + + + + + + + + + + +
+

归还图书

+
+ + +
+ <% + // 从会话中获取逾期天数、罚款金额和图书编号 + Object days = session.getAttribute("days"); + Object fee = session.getAttribute("fee"); + String book = session.getAttribute("book").toString(); + + // 初始化提示信息 + String mes = ""; + String mes2 = ""; + float sum = 0; + + // 根据逾期天数计算罚款 + if (days != null && fee != null) { + int d = Integer.parseInt(days.toString()); + float f = Float.parseFloat(fee.toString()); + if (d < 0) { + mes = "已逾期 " + (-d) + " 天"; + sum = d * f * (-1); // 计算罚款总额 + mes2 = "罚款金额:¥" + sum; + } else { + mes = "还剩 " + d + " 天"; + } + // 将提示信息保存到会话中 + session.setAttribute("mes", mes); + session.setAttribute("mes2", mes2); + } + %> + + +
+ +
+
+ <%= session.getAttribute("mes") %> +
+ <%= session.getAttribute("mes2") %> +
+
+ + +
+ +
+ " + autocomplete="off" class="layui-input"> +
+
+ + + <% + // 查询该图书的借阅记录(未归还) + String sql2 = "select * from borrow_books where return_date is null and book_id = " + book; + ResultSet rs2 = judge.executeQuery(sql2); + String endDate = ""; + while (rs2.next()) { + endDate = rs2.getString("end_date"); + %> +
+ +
+ +
+
+ <% } %> + + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ "> +
+
+ + +
+ +
+
+ + + +
+ +// * * * 05returnSus.jsp + + + 图书归还处理 + + + + + + <% + // 获取表单提交参数 + String book = request.getParameter("bookid"); // 图书编号 + String date1 = request.getParameter("date1"); // 归还日期 + String ill = request.getParameter("ill"); // 违规信息(可选) + String managerid = request.getParameter("managerid"); // 管理员编号 + + // 管理员登录验证 + if (session.getAttribute("manager") != null) { + try { + // 查询图书当前状态 + String sql2 = "select * from books where ID = " + book; + ResultSet rs2 = ret.executeQuery(sql2); + + if (rs2.next()) { + int status = Integer.parseInt(rs2.getString("STATUS")); + + // 图书状态检查(0表示已借出,1表示可借阅) + if (status == 0) { + // 更新借阅记录:设置归还日期、违规信息和处理管理员 + String sql = "update borrow_books " + + "set RETURN_DATE = ?, ILLEGAL = ?, MANAGER_ID = ? " + + "where manager_id is null and BOOK_ID = ?"; + + // 执行更新操作 + int i = ret.executeUpdate(sql, new Object[]{date1, ill, managerid, book}); + + // 更新图书状态为可借阅 + ret.executeUpdate("update books set STATUS = 1 where ID = ?", new Object[]{book}); + + %> + + <% + } else { + %> + + <% + } + } + } catch (SQLException e) { + e.printStackTrace(); + %> + + <% + } + } else { + %> + + <% + } + %> + +//* * * 06borrwoTable.jsp + + + + 借阅记录 + + + + + + + + + + +
+ + + + + + +//* * * 07returnTable.jsp + + + 待归还图书列表 + + + + + + + + + +
+ + + + + + +//* * * 08add.jsp + + + 发布公告 + + + + + + + +
+ +
+ +
+ + required + autocomplete="off" + placeholder="请输入标题" + class="layui-input"> +
+
+ + +
+ +
+ +
+
+ + +
+
+ +
+
+
+ + + +//* * *08edit.jsp + + + + + 公告编辑 + + + + + + <% + // 获取URL参数中的公告ID + String id = request.getParameter("id"); + + // 数据库操作 + Connection connection = null; + PreparedStatement pstmt = null; + ResultSet resultSet = null; + + try { + connection = Base.getConnection(); + // 使用预编译语句查询公告信息 + String sql = "select * from announcement where id=?"; + pstmt = connection.prepareStatement(sql); + pstmt.setString(1, id); + resultSet = pstmt.executeQuery(); + + // 移动到结果集第一条记录 + if (resultSet.next()) { + // 页面后续会使用这些数据 + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + // 释放资源(此处未正确关闭,建议在finally中处理) + } + %> + + +
+ + + + +
+ +
+ " + lay-verify="required" required + autocomplete="off" + placeholder="请输入标题" + class="layui-input"> +
+
+ + +
+ +
+ " + lay-verify="required" + placeholder="请输入公告" + autocomplete="off" + class="layui-input"> +
+
+ + +
+
+ +
+
+
+ + + +//* * *09managerSelf.jsp + + + + 管理员个人资料 + + + + + + + + + + + + + + + + + + + + + + +
+ 管理员基本信息 +
+ <% + // 获取当前登录管理员账号 + String manacc = session.getAttribute("manager").toString(); + // 查询管理员信息(存在SQL注入风险!) + String sql = "select * from manager where ACCOUNT = '" + manacc + "';"; + ResultSet rs = gly.executeQuery(sql); + while (rs.next()) { + %> + +

姓名:<%= rs.getString("name") %>


+

账号:<%= rs.getString("account") %>


+

邮箱:<%= rs.getString("email") %>


+ + + + + + + <% } %> +
+
+ + + + + + + + + + + +
+ + + + + + + + + + +//* * *updateManager.jsp + + + 管理员资料修改处理 + + + + + + <% + // 获取表单提交的参数 + String psw1 = request.getParameter("psw1"); // 新密码 + String psw2 = request.getParameter("psw2"); // 确认密码 + String email1 = request.getParameter("email1"); // 新邮箱 + String email2 = request.getParameter("email2"); // 确认邮箱 + String name1 = request.getParameter("name1"); // 新姓名 + String name2 = request.getParameter("name2"); // 确认姓名 + + // 获取当前登录管理员账号 + String id = session.getAttribute("manager").toString(); + + // 密码修改逻辑 + if (psw1 != null && psw2 != null) { + // 验证密码一致性和非空 + if (psw1.equals(psw2) && !psw1.trim().isEmpty() && !psw2.trim().isEmpty()) { + // 存在SQL注入风险!建议使用预编译语句 + String sql = "update manager set PASSWORD = ? where ACCOUNT = ?"; + try (Connection conn = check.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, psw1); + pstmt.setString(2, id); + int affectedRows = pstmt.executeUpdate(); + + if (affectedRows == 1) { + %> + + <% + } else { + %> + + <% + } + } catch (SQLException e) { + e.printStackTrace(); + %> + + <% + } + } else { + %> + + <% + } + } + // 邮箱修改逻辑 + else if (email1 != null && email2 != null) { + // 验证邮箱一致性和非空 + if (email1.equals(email2) && !email1.trim().isEmpty() && !email2.trim().isEmpty()) { + // 建议添加邮箱格式验证(正则表达式) + String sql = "update manager set EMAIL = ? where ACCOUNT = ?"; + try (Connection conn = check.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, email1); + pstmt.setString(2, id); + int affectedRows = pstmt.executeUpdate(); + + if (affectedRows == 1) { + %> + + <% + } else { + %> + + <% + } + } catch (SQLException e) { + e.printStackTrace(); + %> + + <% + } + } else { + %> + + <% + } + } + // 姓名修改逻辑 + else if (name1 != null && name2 != null) { + // 验证姓名一致性和非空 + if (name1.equals(name2) && !name1.trim().isEmpty() && !name2.trim().isEmpty()) { + String sql = "update manager set NAME = ? where ACCOUNT = ?"; + try (Connection conn = check.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, name1); + pstmt.setString(2, id); + int affectedRows = pstmt.executeUpdate(); + + if (affectedRows == 1) { + %> + + <% + } else { + %> + + <% + } + } catch (SQLException e) { + e.printStackTrace(); + %> + + <% + } + } else { + %> + + <% + } + } else { + %> + + <% + } + %> + +// * * * loginManager.html + + + 图书管理员登录页面 + + + + + + + + + + + + + + + + + + + +
+ +
+

工作人员登录

+ +
+ + + + + + +
+
+
+ + +
+ + + + +
+ + + + +
+ + + + + +// * * * src/main/webapp/index.jsp + + + + Insert title here + + + <% + // 使用response.sendRedirect方法将页面重定向到指定的URL + // 这里将页面重定向到名为04readerFrame.jsp的页面,该页面位于reader目录下 + response.sendRedirect("./reader/04readerFrame.jsp"); + %> + + + + + + + + + + + + + + + +