JavaEE图书管理系统:原生Servlet+JSP实战指南
2026/9/16 13:07:30 网站建设 项目流程

简介:本资源是一个基于JavaEE企业级技术栈开发的完整图书管理系统项目,面向Java初学者与进阶开发者,用于深入理解MVC架构、Web层交互、数据库操作及企业级框架集成。项目采用Servlet/JSP+JDBC或Spring MVC+MyBatis等主流组合实现,涵盖用户管理、图书增删改查、借阅记录等核心功能,并集成Bootstrap前端界面与Spring Security基础权限控制。压缩包共93个文件,含21个Java源码、11个JSP页面、10个XML配置(如struts.xml、web.xml)、21个JAR依赖库及CSS/JS/图片等资源,整体6.62MB,结构清晰,适配Eclipse或IntelliJ IDEA直接导入运行。已有144人学习下载,提供可运行的完整工程骨架、分层代码组织范例及典型企业级技术落地实践,是掌握JavaEE全栈开发流程的优质入门与复现型学习材料。

1. 这不是“又一个Java Web练手项目”:它是一套可部署、可调试、可扩展的JavaEE图书管理骨架

你下载的基于javaee的图书管理系统.zip,表面看是毕业设计常见题,但实际藏着一套被低估的JavaEE工程实践范式——它不依赖Spring Boot自动装配,不靠Maven一键拉取全部依赖,而是用原生Servlet+JSP+JDBC+JSTL构建出清晰分层、可定位、可替换的技术栈。这意味着:你能一眼看清请求如何从HTTP进Filter、经Servlet调度、查DataSource、渲染JSP;也能在Tomcat日志里精准捕获SQL执行耗时、会话超时原因、JNDI绑定失败点。它适合两类人:刚学完《Java Web编程技术》想验证知识闭环的学生,以及需要快速搭建内部文档/资产目录系统、又不想引入复杂框架的运维或DBA。别被.zip后缀迷惑——解压后看到的不是静态HTML,而是web.xml声明式配置、WEB-INF/lib下明确版本的javax.servlet-api-3.1.0.jarmysql-connector-java-5.1.47.jar,以及按MVC拆分的src/com/book/dao/BookDAO.javaWebContent/jsp/list.jsp。这才是JavaEE本该有的样子:可控、透明、无黑盒。

2. 搭建JavaEE运行环境:从JDK到Tomcat再到VS Code的最小可行链路

2.1 JDK与Tomcat版本对齐:为什么必须用JDK 8 + Tomcat 8.5?

JavaEE规范版本与JDK/Tomcat强绑定。基于javaee的图书管理系统.zipweb.xml头声明为<web-app version="3.1">,这对应JavaEE 7规范,要求容器支持Servlet 3.1。而Servlet 3.1的官方兼容列表明确要求:JDK最低版本为1.7,但Tomcat 8.0+才完整实现3.1特性(如异步Servlet、注解式Filter)。实测发现,若用JDK 11+Tomcat 9,@WebServlet("/book")注解可能被忽略,导致404;若用JDK 17+Tomcat 10,则javax.servlet.*包名已升级为jakarta.servlet.*,整个项目编译直接失败。因此,必须锁定JDK 8u202 + Tomcat 8.5.90组合。验证方法:解压Tomcat后进入bin目录,执行version.bat(Windows)或./version.sh(Linux),输出应含Server version: Apache Tomcat/8.5.90JVM Version: 1.8.0_202-b08

提示:不要用java -version单独验证JDK——需确保Tomcat启动脚本中JAVA_HOME指向JDK 8安装路径,而非系统默认JDK。Windows下检查tomcat/bin/setenv.bat,Linux下检查tomcat/bin/setenv.sh,确认set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202(路径需真实存在)。

2.2 VS Code配置JavaEE开发环境:三步完成语言服务、编译与热部署

VS Code本身不内置JavaEE支持,需通过插件链构建完整工作流。核心是三个插件协同:Extension Pack for Java(提供基础语法校验)、Tomcat for Visual Studio Code(管理服务器生命周期)、Language Support for Java(TM) by Red Hat(解析web.xml和JSP标签库)。配置步骤如下:

2.2.1 配置Java Runtime与Project SDK

在VS Code中打开解压后的项目根目录(含srcWebContentbuild.xml的文件夹),按Ctrl+Shift+P调出命令面板,输入Java: Configure Java Runtime,选择JDK 8作为默认JRE。接着右键点击src文件夹 →Java: Configure Classpath→ 在弹出窗口中点击Add Library→ 选择Tomcat 8.5安装目录下的lib文件夹(路径如C:\apache-tomcat-8.5.90\lib),勾选catalina.jarservlet-api.jarjsp-api.jarel-api.jar——这四者是JavaEE Web容器核心API,缺一不可。

2.2.2 配置Tomcat服务器并关联项目

安装Tomcat for Visual Studio Code插件后,侧边栏出现Tomcat图标。点击+ Add Server→ 选择Apache Tomcat→ 浏览到C:\apache-tomcat-8.5.90目录 → 点击Finish。随后右键新添加的服务器 →Add Deployment→ 选择当前项目 → 设置Context Path/book(与web.xml<context-param>一致)→Deploy。此时VS Code会在.vscode/settings.json中自动生成:

{ "tomcat.servers": [ { "name": "Tomcat 8.5", "path": "C:\\apache-tomcat-8.5.90", "deployments": [ { "project": "./", "contextPath": "/book" } ] } ] }
2.2.3 启动与热部署验证

点击Tomcat侧边栏的绿色三角形启动按钮。观察VS Code底部状态栏,当显示Tomcat 8.5: Running且终端输出INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [X] milliseconds时,说明服务就绪。此时访问http://localhost:8080/book,应看到登录页面。修改任意JSP文件(如WebContent/jsp/login.jsp),保存后VS Code会自动触发Reload,无需重启Tomcat——这是Tomcat for VS Code插件监听文件变更并调用Manager App/reload接口实现的。

3. 解析项目结构与核心流程:从web.xml入口到DAO层数据落地

3.1 web.xml驱动的请求路由:为什么Filter优先于Servlet?

web.xml是JavaEE项目的中枢神经。在本系统中,其关键配置有三处:

<!-- 定义全局上下文参数 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/web.xml</param-value> </context-param> <!-- 配置字符编码过滤器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.book.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置前端控制器Servlet --> <servlet> <servlet-name>BookServlet</servlet-name> <servlet-class>com.book.servlet.BookServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>BookServlet</servlet-name> <url-pattern>/book/*</url-pattern> </servlet-mapping>

注意:CharacterEncodingFilter<url-pattern>/*</url-pattern>确保所有请求(包括静态资源)都先经过此Filter,解决中文乱码问题;而BookServlet<url-pattern>/book/*</url-pattern>则将/book/add/book/list等路径交由其处理。执行顺序严格为:Filter chain → Servlet service() → JSP render。若跳过Filter直接访问Servlet,数据库插入中文会变成??,这是初学者最常踩的坑。

3.2 BookServlet的MVC调度逻辑:URL路径如何映射到具体操作?

BookServlet采用传统if-else分支而非注解,代码更易追踪:

// com/book/servlet/BookServlet.java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path = request.getRequestURI(); // 如 /book/list String action = path.substring(path.lastIndexOf("/") + 1); // 提取 list if ("list".equals(action)) { List<Book> books = bookDAO.findAll(); request.setAttribute("bookList", books); request.getRequestDispatcher("/jsp/list.jsp").forward(request, response); } else if ("add".equals(action)) { // 处理新增逻辑... } else if ("delete".equals(action)) { // 处理删除逻辑... } }

关键点在于request.getRequestDispatcher("/jsp/list.jsp").forward(request, response)——这是服务器端跳转,浏览器URL不变(仍为/book/list),且request对象中的属性(如bookList)能传递到JSP。若误用response.sendRedirect("/jsp/list.jsp"),则变为客户端重定向,request属性丢失,JSP中<c:forEach items="${bookList}" var="book">将报空指针异常。

3.3 JDBC连接池配置:为什么用DBCP而不是直接new Connection?

项目使用Apache Commons DBCP 1.4管理数据库连接,在src/jdbc.properties中定义:

driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/bookdb?useUnicode=true&characterEncoding=UTF-8 username=root password=123456 initialSize=5 maxActive=20 maxWait=60000

BookDAO通过BasicDataSource获取连接:

public class BookDAO { private static BasicDataSource dataSource; static { Properties props = new Properties(); props.load(BookDAO.class.getClassLoader().getResourceAsStream("jdbc.properties")); dataSource = new BasicDataSource(); dataSource.setDriverClassName(props.getProperty("driverClassName")); dataSource.setUrl(props.getProperty("url")); dataSource.setUsername(props.getProperty("username")); dataSource.setPassword(props.getProperty("password")); dataSource.setInitialSize(Integer.parseInt(props.getProperty("initialSize"))); dataSource.setMaxActive(Integer.parseInt(props.getProperty("maxActive"))); } public List<Book> findAll() throws SQLException { Connection conn = dataSource.getConnection(); // 从此处获取连接 // ... 执行查询 conn.close(); // 归还连接到池,非真正关闭 return books; } }

注意:conn.close()调用的是DBCP的代理Connection的close()方法,实际将连接放回池中;若直接new DriverManager.getConnection(),每次查询都新建物理连接,100并发时MySQL会报Too many connections错误。

4. 数据库与业务逻辑落地:MySQL建库、表结构及DAO层关键实现

4.1 创建bookdb数据库与book表:字符集与引擎必须匹配

执行以下SQL创建数据库及表(注意utf8mb4字符集):

CREATE DATABASE bookdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE bookdb; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, author VARCHAR(50) NOT NULL, isbn VARCHAR(20), price DECIMAL(10,2) NOT NULL, publish_date DATE, status ENUM('available', 'borrowed', 'lost') DEFAULT 'available', create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

关键点:CHARACTER SET utf8mb4支持emoji和四字节UTF-8字符;ENGINE=InnoDB支持事务和外键(虽本系统未用外键,但为后续扩展预留);status字段用ENUM类型,避免前端传入非法值(如'deleted'),数据库层即拦截。

4.2 BookDAO的CRUD实现:PreparedStatement防注入与结果集映射

BookDAOaddBook()方法体现JavaEE安全最佳实践:

public void addBook(Book book) throws SQLException { String sql = "INSERT INTO book (title, author, isbn, price, publish_date, status) VALUES (?, ?, ?, ?, ?, ?)"; Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, book.getTitle()); // 参数化赋值,杜绝SQL注入 pstmt.setString(2, book.getAuthor()); pstmt.setString(3, book.getIsbn()); pstmt.setBigDecimal(4, book.getPrice()); pstmt.setDate(5, new java.sql.Date(book.getPublishDate().getTime())); pstmt.setString(6, book.getStatus()); pstmt.executeUpdate(); // 执行插入 pstmt.close(); conn.close(); }

对比危险写法:"INSERT INTO book VALUES ('" + book.getTitle() + "', ...)"——若title' OR '1'='1,将导致全表删除。而PreparedStatement预编译SQL,参数仅作为数据传输,不参与SQL语法解析。

4.3 JSP页面的数据绑定:JSTL与EL表达式如何协作渲染列表

WebContent/jsp/list.jsp使用标准标签库展示数据:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>图书列表</title></head> <body> <h2>图书管理</h2> <table border="1"> <tr> <th>ID</th><th>书名</th><th>作者</th><th>价格</th><th>操作</th> </tr> <c:forEach items="${bookList}" var="book"> <tr> <td>${book.id}</td> <td>${book.title}</td> <td>${book.author}</td> <td>${book.price}</td> <td> <a href="/book/delete?id=${book.id}">删除</a> <a href="/book/edit?id=${book.id}">编辑</a> </td> </tr> </c:forEach> </table> </body> </html>

<c:forEach>遍历requestbookList属性(List ),var="book"生成每个Book对象的EL变量;${book.title}通过JavaBean规范调用getTitle()方法。若页面空白,首要检查bookList是否为空——在BookServlet中加System.out.println("Size: " + books.size());验证DAO查询结果

5. 调试与排错实战:定位404、500、乱码三大高频故障

5.1 404错误排查:从URL路径到web.xml映射的逐层验证

当访问http://localhost:8080/book/list返回404,按此顺序检查:

  1. 确认Tomcat是否启动成功:查看logs/catalina.out末尾是否有INFO ... Server startup字样;
  2. 确认应用是否部署成功:访问http://localhost:8080/manager/html(需在conf/tomcat-users.xml中配置manager角色),在应用列表中查找/book,状态应为running
  3. 确认web.xml中servlet-mapping路径<url-pattern>/book/*</url-pattern>意味着/book/list匹配,但/booklist不匹配;
  4. 确认BookServlet类路径com.book.servlet.BookServlet必须存在于WEB-INF/classes/com/book/servlet/BookServlet.class,若VS Code编译后class文件在out/production/...目录,需在VS Code设置中启用"java.configuration.updateBuildConfiguration": "interactive",确保编译输出到WEB-INF/classes

5.2 500错误定位:从堆栈日志到具体行号的精准打击

500错误必看logs/catalina.out。典型场景如数据库连接失败:

Caused by: java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)

此时检查jdbc.propertiesusernamepassword是否与MySQL实际账户一致;若报java.lang.ClassNotFoundException: com.mysql.jdbc.Driver,说明mysql-connector-java-5.1.47.jar未放入WEB-INF/lib——JavaEE项目中JDBC驱动必须放在WEB-INF/lib,不能只配在VS Code的Classpath里

5.3 中文乱码终极解决方案:三处UTF-8强制统一

乱码问题必查三处:

位置配置项正确值验证方式
MySQL客户端my.cnf[client]default-character-set=utf8mb4mysql -u root -p -e "SHOW VARIABLES LIKE 'character%';"
Tomcat连接池jdbc.propertiesurl参数?useUnicode=true&characterEncoding=UTF-8查看BookDAOdataSource.getUrl()输出
JSP页面<%@ page contentType="text/html;charset=UTF-8" %>必须存在且值为UTF-8查看浏览器开发者工具Network选项卡,Response Headers中Content-Type是否含charset=UTF-8

若仍乱码,在CharacterEncodingFilterdoFilter()方法中加System.out.println("Request encoding: " + request.getCharacterEncoding()),确认Filter确实生效。

5.4 表单提交中文变问号:POST与GET的编码差异处理

GET请求(如/book/delete?id=1)的中文参数需在Tomcatconf/server.xml<Connector>标签加URIEncoding="UTF-8"

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />

POST请求(如新增图书表单)由CharacterEncodingFilter处理,但需确保HTML表单<form>未设置accept-charset属性,否则会覆盖Filter设置。验证方法:在BookServlet中打印request.getParameter("title"),若为??,说明编码链断裂。

提示:在BookServletdoPost()开头加request.setCharacterEncoding("UTF-8")是冗余操作——CharacterEncodingFilter已提前执行,此处再设无效,反而暴露对Filter机制理解偏差。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询