
简介基于JDBC、JSP和Servlet技术栈开发的图书管理系统完整工程项目面向Java Web课程设计、毕业设计及期末大作业场景提供从数据库设计到前端页面的全套代码项目包含完整源码、数据库脚本与项目说明文档下载后即可导入运行无需额外修改可帮助有Java基础的学习者快速掌握三层架构开发、数据库交互及页面展示的完整流程。压缩包共包含141个文件主要为Java源码24个java、编译后的class文件48个class及JSP页面10个jsp辅以SQL数据库脚本、相关xml配置、jar依赖库和CSS样式文件整体约5.12MB目录结构清晰便于直接部署和二次学习目前已有100人学习下载。项目已按高分标准完成设计涵盖图书信息管理、学生管理、登录鉴权等核心模块附有项目说明文档便于理解业务逻辑与代码分层无论是作为课程设计提交还是用于自学Servlet与JDBC整合开发都能提供从数据库到前端展示的完整参考路径。1. 基于JDBCJSPServlet的图书管理系统源码到底在解决什么问题对于刚走完Java SE基础、想见识真正Web项目的人来说图书管理系统几乎是最不容易卡住的实战选题。一个“基于JDBCJSPServlet的图书管理系统源码数据库项目说明.zip”本质上就是把三层架构、会话控制、数据库增删改查、表单交互全部浓缩进一个压缩包里。它解决的问题不是图书业务本身而是让你照着一个完整链路把“浏览器点击→Servlet接收参数→JDBC读写MySQL→JSP回显结果”这条主线在本地跑通。适合两类人一是Java课程设计、期末答辩需要交可运行项目的学生二是想找一个干净案例快速熟悉老牌Java Web技术栈的从业者。下文我会按源码包常见结构、核心实现、部署命令和踩坑顺序把它变成能照着做的东西。2. 读懂项目骨架从web.xml到三层架构源码包里的文件该怎么排拿到zip别急着启动。这类源码包我见多了命名方式五花八门内部结构却高度趋同。拆开之后通常不是只有一个文件夹而是能看到三个组成部分源码目录src、Web资源目录WebContent 或 web名字取决于你用的是Eclipse还是IDEA的Web模板、数据库目录database 或 sql。有的作者还会额外塞一份“项目说明.docx”里面写建表语句、默认管理员账号和部署步骤这份文档优先级最高先读它。先看目录结构用tree命令看最直观。常见结构中src下面按包名组织典型为com.xxx.dao、entity、servlet、util。Web目录下WEB-INF里必须有web.xmlJSP页面通常放在WebContent或src/main/webapp下。数据库目录下放init.sql。我一般先刷一眼web.xml确认Servlet映射路径和过滤器再决定从哪里下手。图书管理系统/ ├── src │ └── com │ └── book │ ├── dao # BookDao、UserDao所有SQL都在这层 │ ├── entity # Book、Admin一张表一个Java类 │ ├── servlet # BookListServlet、AddBookServlet、DeleteBookServlet... │ └── util # DBUtil唯二改代码的位置 ├── WebContent │ ├── WEB-INF │ │ ├── lib # mysql-connector-java.jar 放这里 │ │ └── web.xml # Servlet映射、欢迎页 │ ├── bookList.jsp # 列表页遍历结果集 │ ├── addBook.jsp # 添加表单 │ └── login.jsp # 管理员登录 └── database └── library.sql # 建库、建表、插入管理员账号这段结构并不是某份特定源码的目录而是这类项目最常见的一种组织方式。Entity层对应数据库表字段一个字段一个私有属性加getter/setterDAO层专门写JDBC操作把SQL字符串、PreparedStatement、结果集遍历都封装成方法Servlet层负责接收请求、转发到JSPJSP只做展示。这样做的好处是数据库改动不用动Servlet页面改动不用动Java逻辑课程设计答辩时也能往“三层架构”上靠。还有一点要注意zip里的项目说明如果只有README.txt也别嫌简陋里面常写的数据库连接账号密码、Tomcat版本、JDK版本是避免后面配置错的救命信息。如果作者没写就需要自己按默认配置测试第4章我会重点讲。2.1 建库脚本与JDBC连接参数先让MySQL有库可连源码包里的database/library.sql是整个系统的基础没有它程序一启动就报“Table library.book doesnt exist”。我建议先手动执行而不是等程序自动建表。常见的建表语句长这样CREATE DATABASE IF NOT EXISTS library DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; USE library; DROP TABLE IF EXISTS book; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, book_name VARCHAR(100) NOT NULL COMMENT 书名, author VARCHAR(50) DEFAULT NULL COMMENT 作者, publisher VARCHAR(100) DEFAULT NULL COMMENT 出版社, price DECIMAL(10,2) DEFAULT 0.00 COMMENT 价格, stock INT DEFAULT 0 COMMENT 库存, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); DROP TABLE IF EXISTS admin; CREATE TABLE admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL ); INSERT INTO admin(username, password) VALUES (admin, 123456);这段脚本里把字符集强制为utf8mb4不是utf8原因是utf8mb4才是完整的四字节UTF-8编码能存表情和生僻字而MySQL的utf8是utf8mb3容易在插入特殊字符时翻车。建表后先插入一条管理员账号方便登录模块直接可用。执行方式是打开mysql命令行或Navicat也可以直接用source命令source D:/library.sql。有了表之后接下来就是源码里最关键的连接工具类——DBUtil。这是JSPServlet项目中改名最少的类常见实现如下package com.book.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/library ?useUnicodetruecharacterEncodingUTF-8 useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new RuntimeException(MySQL驱动加载失败请确认jar包已加入lib目录, e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }代码逻辑说明static块在类加载时执行一次Class.forName把驱动类加载进来MySQL 8.0以后驱动类名是com.mysql.cj.jdbc.Driver如果是MySQL 5.x要改成com.mysql.jdbc.Driver。URL里那一串参数不是可有可无的characterEncodingUTF-8解决写入中文变成问号useSSLfalse跳过SSL握手不然新版MySQL会警告或报错serverTimezoneAsia/Shanghai解决JDBC与MySQL的时区偏差否则会抛“Server returns invalid timezone”。USER和PASSWORD要改成你本地MySQL的实际密码很多同学在这里直接改数据库密码匹配但更规范的做法是不要让密码裸奔在Java源码里至少提到配置文件里。不过课程设计阶段的DBUtil这么写也够用JDBC连接MySQL这一步走通后续操作的基座就稳了。2.2 从web.xml读请求路由原来每个URL都绑了一个Servlet先说不推荐直接看源码逻辑推荐先打开WebContent/WEB-INF/web.xml看servlet-mapping。这段配置决定了URL与Java类的对应关系常见内容如下?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1 welcome-file-list welcome-filelogin.jsp/welcome-file /welcome-file-list servlet servlet-nameBookListServlet/servlet-name servlet-classcom.book.servlet.BookListServlet/servlet-class /servlet servlet-mapping servlet-nameBookListServlet/servlet-name url-pattern/list/url-pattern /servlet-mapping servlet servlet-nameAddBookServlet/servlet-name servlet-classcom.book.servlet.AddBookServlet/servlet-class /servlet servlet-mapping servlet-nameAddBookServlet/servlet-name url-pattern/addBook/url-pattern /servlet-mapping /web-app解释每个servlet元素先声明实现类再通过servlet-mapping把访问路径绑定到名字上。于是/addBook这个URL不再直接指向某个JSP而是进入AddBookServlet的doPost或doGet。welcome-file-list决定访问根路径时默认打开login.jsp。如果你发现源码里用了WebServlet注解那web.xml就可以很瘦这两种方式效果一样但老项目喜欢在web.xml里集中管理。读懂了这层你就能根据URL反查Servlet类再通过Servlet类里的转发语句找到JSP。整条链路不再是黑匣子下一章就用核心链路把它补全。3. 把图书增删改查跑起来ServletJDBC的核心链路与最小实现结构看明白了这一章动代码。图书管理系统最核心的是数据库增删改查绕不开两条线一条是Java侧用JDBC写SQL另一条是Servlet把HTTP请求转成DAO方法调用。我以“图书列表”和“新增图书”两个功能来拆解删除和编辑就是照葫芦画瓢。3.1 实体类与DAO方法表和对象之间的手动映射实体类是DAO操作的最小单位。源码包里常见Book.java内容不复杂但字段必须和数据库列一一对应。以下是一份最实用的写法和对应DAO方法package com.book.entity; import java.math.BigDecimal; import java.util.Date; public class Book { private Integer id; private String bookName; private String author; private String publisher; private BigDecimal price; private Integer stock; private Date createTime; public Book() {} public Integer getId() { return id; } public void setId(Integer id) { this.id id; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName bookName; } // 其余字段的getter/setter按同名映射生成 // author、publisher、price、stock、createTime }逻辑说明数据库字段名为book_nameJava属性名为bookName这是Java命名习惯靠rs.getString(book_name)和setBookName()两个调用手动映射。BigDecimal对应数据库的DECIMAL避免浮点数造成价格精度问题。Date对应DATETIME将来在页面显示可以用SimpleDateFormat格式化。有了BookDAO层就能写查询方法。这里我故意用PreparedStatement而不是Statement能省掉字符串拼接和单引号问题这也是源码包里“标准答案”的升级版package com.book.dao; import com.book.entity.Book; import com.book.util.DBUtil; import java.sql.*; import java.util.ArrayList; import java.util.List; public class BookDao { public ListBook findAll() { ListBook list new ArrayList(); String sql SELECT id, book_name, author, publisher, price, stock, create_time FROM book ORDER BY id DESC; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Book b new Book(); b.setId(rs.getInt(id)); b.setBookName(rs.getString(book_name)); b.setAuthor(rs.getString(author)); b.setPublisher(rs.getString(publisher)); b.setPrice(rs.getBigDecimal(price)); b.setStock(rs.getInt(stock)); list.add(b); } } catch (SQLException e) { e.printStackTrace(); } return list; } }代码逻辑说明try-with-resources写法是JDK 7之后的优势Connection、PreparedStatement、ResultSet都实现了AutoCloseable方法结束后自动关闭不用手写finally释放避免连接泄漏。executeQuery()执行查询返回结果集rs.next()每调用一次游标移到下一行字段名和SQL里select的列名对应。拿到结果后封装成Book对象并放进List。这里的ORDER BY id DESC让新增图书显示在前面相比默认insert顺序页面对用户更友好源码包如果没有自己加上也无妨。参数说明如果表名、列名与这里不同改SQL字符串就行但要同步改实体类和DAO方法否则运行期才发现字段取不到排错成本更高。3.2 Servlet把HTTP分流到DAO再把结果转给JSPJSP不能直接调用DAO中间要经过Servlet。列表功能的Servlet是最标准的写法package com.book.servlet; import com.book.dao.BookDao; import com.book.entity.Book; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; public class BookListServlet extends HttpServlet { private final BookDao bookDao new BookDao(); Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ListBook books bookDao.findAll(); request.setAttribute(books, books); request.getRequestDispatcher(/bookList.jsp).forward(request, response); } }逻辑说明doGet处理GET请求当用户访问/list时Servlet先调用DAO查询全部图书把结果塞进request作用域然后forward到bookList.jsp。forward是服务器内部转发浏览器地址栏不变也不是重定向所以页面可以拿到request里的books。注意代码没有调用response.getWriter()因为没有直接输出而是交给JSP渲染。参数说明request.setAttribute的key“books”必须和JSP里取的名字一致getRequestDispatcher路径要带前导斜杠且指向WebContent根下的JSP。如果JSP放在WEB-INF/views里路径要写成/WEB-INF/views/bookList.jsp图书管理系统这种非敏感页面一般不藏。新增图书的Servlet处理POST请求写法也很有代表性Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String name request.getParameter(bookName); String author request.getParameter(author); // 省略了价格、库存的解析实际要处理空串和数字格式 Book book new Book(); book.setBookName(name); book.setAuthor(author); new BookDao().insert(book); response.sendRedirect(request.getContextPath() /list); }逻辑说明doPost第一行设置字符编码保证中文表单参数不是乱码。getParameter(bookName)读取的是表单里对应的name值。组装Book对象后调用DAO.insert()最后用sendRedirect重定向到列表页防止按F5刷新时重复提交表单。重定向是两次请求表单数据已被丢弃这是它与forward最典型的区别。很多源码包在Servlet里直接塞业务代码导致Action类膨胀理解这条链路后可以把公共逻辑抽到DAO这是后话了。3.3 JSP页面用EL表达式把数据渲染出来列表JSP是理解整套技术的最后一环。常见写法如下% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title图书列表/title /head body table border1 tr thID/thth书名/thth作者/thth出版社/thth价格/thth库存/thth操作/th /tr c:forEach items${books} varbook tr td${book.id}/td td${book.bookName}/td td${book.author}/td td${book.publisher}/td td${book.price}/td td${book.stock}/td td a hrefeditBook?id${book.id}编辑/a a hrefdeleteBook?id${book.id} onclickreturn confirm(确认删除)删除/a /td /tr /c:forEach /table a hrefaddBook.jsp新增图书/a /body /html逻辑说明c:forEach是JSTL标签items${books}对应Servlet里setAttribute的Listvarbook定义循环变量${book.bookName}调用Book对象的getBookName方法。这套写法比% %脚本片段干净也是源码包里常见的改进方向。如果手头没有jstl.jar和standard.jar可以退回Java脚本片段但EL表达式是JSP 2.0自带不依赖JSTL能用。参数说明pageEncodingUTF-8要写对否则中文字符在页面渲染时变成“锟斤拷”一类乱码。操作列的编辑、删除链接都用GET带参数这是幂等操作的简单做法删除链接加onclick确认弹窗属于前端小兜底。掌握了列表和新增编辑通过id把图书查出来显示在表单里提交后走update删除通过id执行DELETE。路径摸熟后后面所有功能只是重复这三层。4. 部署到Tomcat的完整步骤从源码zip到浏览器能访问代码读得再多不如真正把它跑起来。这一章写的是我日常部署这类项目的步骤覆盖环境选型、导入项目和初始化数据库三个关键动作。很多同学卡在第一步其实是环境组合没选对。4.1 环境版本怎么选JDK、Tomcat、MySQL的搭配逻辑JSPServlet是老技术栈版本兼容有讲究。先说我的推荐JDK 1.8或11、Tomcat 9.0.x、MySQL 5.7或8.0。这三个版本配到一起最稳原因是Tomcat 9用的是Servlet 4.0规范包名还是javax.servlet和绝大多数课程设计源码一致。如果你误用了Tomcat 10它的Servlet包名换成了jakarta.servlet老源码里import javax.servlet会直接编译失败这是最常遇到的版本坑。MySQL方面5.7和8.0都行但驱动类名和URL参数不同5.7用com.mysql.jdbc.Driver不需要serverTimezone8.0用com.mysql.cj.jdbc.Driver需要serverTimezoneAsia/Shanghai。如果源码里都是老驱动类名而本机是MySQL 8启动时就会报“Loading class com.mysql.jdbc.Driver”这类错误正确做法是下载一个mysql-connector-java 8.0.x的jar包然后把驱动类名改成新的。Tomcat端口默认8080如果被占用可以在conf/server.xml里改端口访问路径就是http://localhost:8080/项目名/。4.2 导入IDEA并修复jar依赖这里最容易翻车拿到源码我一般不建议直接运行而是先在IDEA里导入。步骤是解压zip打开IDEA选Open找到解压后的根目录等待项目索引完成。如果没有用Maven构建只是普通Web项目IDEA通常不认识要手动做三件事一是Project Structure里把Project SDK选成1.8Language level选8二是右键项目Add Framework Support → Web Application生成WEB-INF与web.xml的识别三是把mysql-connector-java.jar拷贝到WEB-INF/lib下然后右键jar → Add as Library。确认驱动jar有没有进最终部署包最可靠的办法是看Artifacts配置展开Project Structure → Artifacts在WEB-INF/lib里能看到驱动才说明打进去了。很多同学代码编译不报错但Tomcat启动后报ClassNotFound就是因为编辑器里能引用到jar部署时jar没有跟随Artifacts发布。检查这个黑匣子通常花不了两分钟但能省下一个下午。# 验证jar是否进入部署目录如果是IDEA默认out目录 find . -name mysql-connector-java*.jar逻辑说明find命令在当前工作目录里递归找驱动jar如果只出现在源码目录而out/artifacts目录里没有就说明Artifacts构建范围没包含lib。解决办法是改Artifacts的Output Layout把lib目录直接拖到部署包根下。如果源码自带Maven pom.xml那就简单得多在pom.xml里加上依赖即可。但很遗憾很多课程设计源码并不用Maven而是手拷jar所以刚才那套手工操作反而更通用。4.3 初始化数据库mysql命令导入和连接参数修改数据库初始化别用Navicat模板导入命令行更直观。第一步是进入mysql客户端创建数据库并导入脚本mysql -uroot -p # 输入密码后执行 source D:/workspace/library/database/library.sql; show databases; use library; show tables;常用命令说明source后面跟绝对路径分隔符用/。执行后library库出现book和admin表表示数据导入成功。此时还可以顺手查一下默认账号select * from admin;确认有一条admin记录。这些mysql数据库常用命令足够支撑后续排查。修改Java里连接字符串时我只改三个位置DBUtil的URL、用户名、密码。常见错误是把localhost写成127.0.0.1导致连接不上其实两者通常等价但权限绑定到host时可能不同。如果连接的是远程数据库把localhost换成远程IP并给MySQL用户授权远程访问GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY 123456; FLUSH PRIVILEGES;授权说明默认root只允许localhost登录源码里密码不是本机密码就报Access denied。如果不想动密码也可以直接改DBUtil里的密码与本地root一致。注意MySQL 8的授权语法和老版本不同IDENTIFIED BY需要分开写上面语句在MySQL 8里可能要改成先创建用户再授权。最后启动TomcatIDEA里配置Tomcat ServerDeployment选择exploded warApplication context设为/library启动后访问http://localhost:8080/library/login.jsp。如果看到登录页说明JDBC连接MySQL全链路通了如果报错下一章就是排查导航。5. 避坑与排查5个让图书管理系统翻车的典型问题我把这几年遇到最多的运行期问题整理成五条全部是“现象→原因→解决”的结构每条都对应一条真实排查路径。你按顺序对照大多数问题五分钟内能定位。这里不想讲大道理只写血泪经验里最值得抄的部分。5.1 现象Tomcat启动时报ClassNotFoundException: com.mysql.cj.jdbc.Driver原因驱动jar不在WEB-INF/lib目录或者IDE没有把它放进Artifacts。程序运行时是Tomcat在加载类不是编译器在加载编译找不到类和运行找不到类是两回事。解决下载对应版本的mysql-connector-java.jar放到WEB-INF/lib。如果用的是Maven添加mysql-connector-j依赖后刷新然后务必到Artifacts里确认Output Layout包含lib。还有一个检测技巧部署后到Tomcat的webapps/项目名/WEB-INF/lib目录看jar必须实际存在别只看编译不报错就放心。这种问题最常见的迷惑点在于刚才编译运行都正常一加Tomcat就崩其实是IDE把依赖分成了“编译期”和“运行期”两份。5.2 现象页面和数据库都是中文乱码插入的姓名变问号原因字符集在三层没有统一。常见错位是JSP文件头没写pageEncoding或者数据库连接URL缺少characterEncoding还可能是HTML表单没指定accept-charset。解决JSP第一行设置% page contentTypetext/html;charsetUTF-8 %数据库连接URL加useUnicodetruecharacterEncodingUTF-8数据库表默认字符集用utf8mb4。如果MySQL里已经是乱码改连接参数后要把旧数据删除重新插入因为数据本身已损坏不是换个显示方式就能回来。另外在Servlet的doPost第一行加request.setCharacterEncoding(UTF-8)这是新手最容易漏的一行因为只改JSP和数据库表单POST过来的中文仍然可能乱。5.3 现象点击新增提交后Servlet拿到的是null原因JSP表单里input的name和Servlet里getParameter参数名不一致。比如表单写namebookNameServlet里写成getParameter(name)结果自然是null。另一个常见坑是methodget导致中文参数在URL里被编码过滤器和解码顺序不对也会拿不到。解决检查表单每个input的name属性与Servlet代码逐一对齐。搜索框、编辑框都要注意。如果用了methodget且项目里配了编码过滤器确保Filter先于Servlet执行并在Filter里设置request编码。最简单的办法是表单都写methodpost从源头减少编码参与。还有一个容易被忽略的地方Servlet里把request.getParameter值直接赋给Integer当表单字段为空时抛NumberFormatException表现为500而不是null这种情况可以先转字符串再判空。5.4 现象JDBC连接报Communications link failure 或者 Access denied for user rootlocalhost原因前者多为MySQL端口不对、数据库服务没启动或URL里的serverTimezone缺失后者是账号密码错误或root账号不允许当前IP登录。MySQL 8对密码插件改为caching_sha2_password老驱动也会导致认证失败。解决先确认MySQL服务已启动mysql -uroot -p能进入客户端说明服务正常再用status看端口。URL里端口3306要匹配。如果报Access denied在DBUtil里把密码改成正确密码或者用root用户登录后执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;这是兼容老驱动的常用办法。对于serverTimezone解决是增加时区参数或改全局时区set global time_zone 08:00;。这条问题在知乎上被问烂了十个报错里有七个是时区要先用排除法把时区补上去再查别的。5.5 现象Tomcat 10启动报错 Servlet启动失败NoClassDefFoundError: javax/servlet/...原因项目源码用的是javax.servlet规范但Tomcat 10已经迁移到Jakarta EE 9类库包名全部改成了jakarta.servlet。老代码直接跑自然找不到类。解决要么把Tomcat换回9.0.x要么把源码里的import javax.servlet.*改成import jakarta.servlet.*同时web.xml的命名空间也要改。课程设计用前者最快因为不需要动代码。这里不建议硬扛用Tomcat 10兼容成本太高收益不值得。很多人以为Tomcat版本没有区别其实从Servlet API命名空间开始这就是一道分水岭。新手看到NoClassDefFoundError先别慌看错误里是javax还是jakarta立刻就能定位。6. 从跑通到改造给图书系统加分的三件小事跑通只是起点。课程设计答辩时“能运行”和“设计得好”是两回事。我建议你做完以下三件小事既提升质量也是给自己攒经验。第一件是验证基础功能用浏览器登录默认账号新增一本图书修改书名删除一条记录最后通过查询功能找到刚才那条数据。如果全部通过说明JDBCServlet链路闭环了。按这个顺序覆盖增删改查四个方向任何一环报错都能立即暴露在哪一层。第二件是预防SQL注入把DAO里所有Statement拼接改成PreparedStatement最经典的对比就在登录查询里// 错误写法踩过的坑用户名传 or 11 直接能登进去 String sql SELECT * FROM admin WHERE username name AND password pwd ; // 正确写法占位符由驱动预编译 PreparedStatement ps conn.prepareStatement( SELECT * FROM admin WHERE username? AND password?); ps.setString(1, name); ps.setString(2, pwd); ResultSet rs ps.executeQuery();第三件是加分技巧在列表页加分页。DAO里查询时加LIMIT ? OFFSET ?Servlet接收page参数计算起始行JSP显示上一页/下一页链接。这个改动量不大但会让答辩老师觉得你理解数据量对查询的影响。这三件小事里我最想强调第二件。有一次我帮人排查“图书管理系统被同学用万能密码登进去”的问题发现就是登录DAO里用了字符串拼接。那天起我写JDBC从来没有再犯过。希望帮到你。本文还有配套的精品资源点击获取