1. 项目背景与核心需求
这个JavaWeb图书管理系统实训项目是典型的Servlet技术实战案例,主要面向计算机专业学生和JavaWeb初学者。作为课程作业,它需要实现一个完整的图书借阅管理流程,包含管理员和普通用户双端操作。从实际教学经验来看,这类作业的难点通常集中在三个层面:
- Servlet控制层设计:如何合理划分Servlet处理各类请求
- 会话管理:用户登录状态维护与权限控制
- 数据库交互:MySQL表设计与CRUD操作实现
我在指导类似项目时发现,90%的学生问题都出在Servlet与JSP的配合上。比如常见的"HTTP 404"错误,往往是因为@WebServlet注解路径配置不当导致的。
2. 核心Servlet设计解析
2.1 控制层架构设计
项目采用了经典的MVC模式,Servlet作为Controller层核心。观察源码可以看到几个关键设计点:
- 每个功能模块对应独立的Servlet类
- 使用
@WebServlet注解配置URL映射 - 通过
doGet/doPost方法区分请求类型
以图书添加功能为例,AddBookServlet的处理流程如下:
java复制@WebServlet("/AddBookServlet")
public class AddBookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
// 1. 设置编码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 2. 获取表单参数
String card = request.getParameter("card");
// ...其他参数获取
// 3. 调用DAO层
BookDao bookdao = new BookDao();
bookdao.addBook(card, name, type, autho, press, num);
// 4. 重定向
response.sendRedirect("/manage_books/books/admin/admin_books.jsp");
}
}
经验提示:在实际开发中,建议使用Filter统一设置编码,而不是在每个Servlet中重复设置。这样可以避免遗漏导致的中文乱码问题。
2.2 请求分发技巧
项目中有个巧妙的设计是tip参数的使用,它解决了同一个Servlet需要服务不同页面的问题。例如在selectServlet中:
java复制int tip = Integer.parseInt(request.getParameter("tip"));
String url = "";
if (tip == 1) { // 管理员界面
url = response.encodeURL("/books/admin/admin_books.jsp");
} else { // 用户界面
url = response.encodeURL("/books/user/select.jsp");
}
request.getRequestDispatcher(url).forward(request, response);
这种设计虽然简单有效,但在大型项目中更推荐使用前端控制器模式(Front Controller),通过一个统一的Servlet来集中处理请求分发。
3. 数据库交互实现
3.1 DAO层设计
项目采用了经典的DAO模式,每个实体类对应一个DAO类。以BookDao为例,核心方法包括:
java复制public class BookDao {
// 添加图书
public void addBook(String card, String name, String type,
String autho, String press, int num) {
// JDBC操作...
}
// 模糊查询
public ArrayList<Book> getLikeList(String name) {
// 构建SQL语句
String sql = "select * from book where name like ?";
// 执行查询并返回结果集
}
}
常见问题:很多学生在实现DAO时容易犯两个错误:一是没有关闭数据库连接导致资源泄露,二是SQL语句拼接不当引发注入风险。建议使用try-with-resources和PreparedStatement来避免这些问题。
3.2 事务管理
项目中借书和还书操作涉及多个表的更新,但源码中缺少显式的事务控制。在实际开发中应该这样改进:
java复制Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false); // 开启事务
// 执行多个SQL操作
bookdao.borrowBook(conn, bid, admin);
recorddao.addRecord(conn, bid, admin);
conn.commit(); // 提交事务
} catch (SQLException e) {
if(conn != null) conn.rollback(); // 回滚
throw e;
} finally {
if(conn != null) conn.close();
}
4. 会话管理与安全
4.1 用户认证实现
登录认证采用Session机制,关键代码如下:
java复制HttpSession session = request.getSession();
session.setAttribute("uid", user.getId()); // 存储用户ID
在后续请求中通过检查Session来判断用户状态:
java复制String uid = (String) session.getAttribute("uid");
if(uid == null) {
response.sendRedirect("login.jsp");
return;
}
4.2 权限控制缺陷
当前实现存在一个安全隐患:管理员功能仅通过前端页面控制,后端没有进行权限校验。应该添加Filter进行统一检查:
java复制public class AdminFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
String role = (String) request.getSession().getAttribute("role");
if(!"admin".equals(role)) {
((HttpServletResponse)res).sendError(403);
return;
}
chain.doFilter(req, res);
}
}
5. 项目优化建议
5.1 代码结构优化
建议将项目重构为以下包结构:
code复制src/
├── main/
│ ├── java/
│ │ ├── controller/ // Servlet类
│ │ ├── dao/ // 数据访问层
│ │ ├── model/ // 实体类
│ │ ├── service/ // 业务逻辑层
│ │ └── util/ // 工具类
│ └── webapp/ // JSP和静态资源
5.2 使用连接池
替换原始的JDBC连接获取方式,采用DBCP或HikariCP连接池:
xml复制<!-- pom.xml添加依赖 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
5.3 引入日志系统
添加Log4j2记录运行日志:
java复制import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class AddBookServlet extends HttpServlet {
private static final Logger logger = LogManager.getLogger();
protected void doPost(...) {
logger.info("开始添加图书:{}", name);
try {
// 业务逻辑
} catch (Exception e) {
logger.error("添加图书异常", e);
}
}
}
6. 典型问题排查指南
6.1 中文乱码问题
如果出现表单提交中文乱码,检查三个地方:
- JSP页面头部:
<%@ page contentType="text/html;charset=UTF-8" %> - Servlet请求处理前:
request.setCharacterEncoding("UTF-8") - 数据库连接字符串:
jdbc:mysql://...?useUnicode=true&characterEncoding=UTF-8
6.2 404错误排查
当出现"HTTP 404"时,按以下步骤检查:
- 确认URL路径与
@WebServlet注解配置一致 - 检查web.xml中是否配置了
<metadata-complete>false</metadata-complete> - 确保Servlet类在正确的包路径下
6.3 数据库连接失败
常见原因和解决方案:
- 驱动未加载:检查是否将JDBC驱动jar包放入WEB-INF/lib
- 连接字符串错误:验证IP、端口、数据库名
- 权限问题:检查数据库用户是否有访问权限
我在实际项目部署时遇到过MySQL时区问题,可以在连接字符串中添加:serverTimezone=Asia/Shanghai
7. 扩展功能实现思路
7.1 添加分页功能
改造查询方法,增加分页参数:
java复制public List<Book> getBooksByPage(int pageNum, int pageSize) {
String sql = "select * from book limit ?,?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, (pageNum-1)*pageSize);
stmt.setInt(2, pageSize);
// 执行查询...
}
}
前端页面添加分页导航条,计算总页数并传递页码参数。
7.2 实现图书封面上传
- 表单设置
enctype="multipart/form-data" - 使用Apache Commons FileUpload处理文件
- 将文件保存到服务器指定目录
- 在数据库中存储文件路径
java复制// 在Servlet中处理上传
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) { // 文件字段
String fileName = new File(item.getName()).getName();
String filePath = UPLOAD_DIR + File.separator + fileName;
item.write(new File(filePath));
// 保存路径到数据库
}
}
这个图书管理系统项目虽然基础,但涵盖了JavaWeb开发的多个核心知识点。在实际开发中,建议逐步引入Spring框架来简化开发,但理解这些底层原理对于成为合格的后端开发者至关重要。
