1. 项目背景与学习价值
作为一名从黑马程序员JavaWeb课程走过来的开发者,我深知部门管理模块在整个课程体系中的重要性。这个看似简单的CRUD案例,实际上涵盖了JavaWeb开发中最核心的技术栈。记得当初第一次接触这个案例时,我花了整整三天才真正理解Servlet和JSP的配合机制。
部门管理模块之所以被选为入门案例,是因为它具备以下典型特征:
- 基础数据模型简单(仅包含部门编号、名称等字段)
- 业务逻辑清晰(增删改查)
- 前端交互完整(表单提交、数据展示)
- 后端处理全面(Servlet、JDBC、Filter等)
这个案例在黑马课程中通常安排在JavaWeb学习的中期阶段,要求学员已经掌握:
- Java基础语法和面向对象编程
- MySQL基础操作
- HTML/CSS/JavaScript前端三件套
- Tomcat服务器的基本使用
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境准备
2.1 基础工具链配置
根据黑马课程的一贯风格,推荐使用以下开发环境组合:
- IDE:IntelliJ IDEA Ultimate 2023.2(社区版也可)
- JDK:Java 17 LTS版本(与课程保持同步)
- 构建工具:Maven 3.8.6(配置阿里云镜像)
- 数据库:MySQL 8.0.33(建议使用Docker部署)
注意:避免使用最新版本的开发工具,某些插件可能存在兼容性问题。我在实际教学中发现,使用与课程完全一致的版本可以避免80%的环境问题。
2.2 项目骨架搭建
创建Maven webapp项目时,需要特别注意目录结构:
code复制dept-manage
├── src
│ ├── main
│ │ ├── java # Java源代码
│ │ ├── resources # 配置文件
│ │ └── webapp # 前端资源
│ │ ├── WEB-INF # 保护目录
│ │ └── static # 静态资源
└── pom.xml # 项目依赖
关键pom依赖配置示例:
xml复制<dependencies>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- JSTL标签库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
3. 数据库设计与实现
3.1 数据表结构设计
部门管理模块的核心表设计应包含以下字段:
sql复制CREATE TABLE `dept` (
`deptno` int NOT NULL AUTO_INCREMENT COMMENT '部门编号',
`dname` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '部门名称',
`loc` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '部门位置',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`deptno`),
UNIQUE KEY `uk_dname` (`dname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
设计要点说明:
- 使用自增主键而非业务编号,避免修改带来的连锁反应
- 部门名称添加唯一约束,防止数据重复
- 添加审计字段便于后期维护
- 字符集使用utf8mb4以支持emoji等特殊字符
3.2 JDBC工具类封装
黑马课程中通常会封装一个基础的JDBCUtils类,这里分享几个优化点:
java复制public class JDBCUtils {
private static DataSource dataSource;
static {
try {
// 使用Druid连接池替代原生JDBC
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://localhost:3306/company?useSSL=false");
druidDataSource.setUsername("root");
druidDataSource.setPassword("123456");
druidDataSource.setInitialSize(5);
druidDataSource.setMaxActive(10);
dataSource = druidDataSource;
} catch (Exception e) {
throw new RuntimeException("初始化连接池失败", e);
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 新增带事务的获取连接方法
public static Connection getTransactionConnection() throws SQLException {
Connection conn = getConnection();
conn.setAutoCommit(false);
return conn;
}
}
4. 核心功能实现
4.1 部门列表展示
Servlet处理逻辑示例:
java复制@WebServlet("/dept/list")
public class DeptListServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
List<Dept> depts = new DeptDao().listAll(conn);
// 使用RequestDispatcher进行请求转发
request.setAttribute("deptList", depts);
request.getRequestDispatcher("/WEB-INF/jsp/dept/list.jsp").forward(request, response);
} catch (SQLException e) {
throw new ServletException("数据库查询失败", e);
} finally {
JDBCUtils.close(conn);
}
}
}
JSP页面关键代码:
jsp复制<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table class="table table-striped">
<thead>
<tr>
<th>部门编号</th>
<th>部门名称</th>
<th>所在地</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${deptList}" var="dept">
<tr>
<td>${dept.deptno}</td>
<td>${dept.dname}</td>
<td>${dept.loc}</td>
<td>
<a href="/dept/edit?deptno=${dept.deptno}" class="btn btn-sm btn-primary">编辑</a>
<a href="/dept/delete?deptno=${dept.deptno}"
class="btn btn-sm btn-danger"
onclick="return confirm('确定删除该部门吗?')">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
4.2 部门新增功能
表单提交时需要特别注意字符编码问题。推荐在Servlet中添加Filter:
java复制@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request, response);
}
}
新增部门的Service层逻辑应该包含业务校验:
java复制public class DeptService {
public void addDept(Dept dept) throws BusinessException {
// 参数校验
if (StringUtils.isBlank(dept.getDname())) {
throw new BusinessException("部门名称不能为空");
}
// 重复性校验
if (deptDao.existsByName(dept.getDname())) {
throw new BusinessException("部门名称已存在");
}
// 数据持久化
deptDao.save(dept);
// 记录操作日志
logService.recordOperation("新增部门: " + dept.getDname());
}
}
5. 常见问题与解决方案
5.1 中文乱码问题
乱码问题通常出现在三个环节:
- JSP页面编码:确保页面头部声明
jsp复制<%@ page contentType="text/html;charset=UTF-8" language="java" %> - Tomcat配置:在server.xml的Connector中添加
xml复制
URIEncoding="UTF-8" - MySQL配置:检查数据库连接字符串是否包含
code复制characterEncoding=UTF-8
5.2 事务管理问题
部门删除操作通常需要处理关联数据,应该使用事务:
java复制public void deleteDept(int deptno) throws BusinessException {
Connection conn = null;
try {
conn = JDBCUtils.getTransactionConnection();
// 检查是否有员工关联
if (empDao.countByDeptno(conn, deptno) > 0) {
throw new BusinessException("该部门下仍有员工,无法删除");
}
// 执行删除
deptDao.delete(conn, deptno);
// 提交事务
conn.commit();
} catch (SQLException e) {
JDBCUtils.rollback(conn);
throw new BusinessException("删除部门失败", e);
} finally {
JDBCUtils.close(conn);
}
}
5.3 并发修改问题
使用乐观锁解决并发修改问题:
- 在dept表中添加version字段
- 更新时检查版本号
sql复制UPDATE dept
SET dname=?, loc=?, version=version+1
WHERE deptno=? AND version=?
对应的Java代码:
java复制public boolean updateDept(Dept dept) throws SQLException {
String sql = "UPDATE dept SET dname=?, loc=?, version=version+1 WHERE deptno=? AND version=?";
try (Connection conn = JDBCUtils.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, dept.getDname());
ps.setString(2, dept.getLoc());
ps.setInt(3, dept.getDeptno());
ps.setInt(4, dept.getVersion());
return ps.executeUpdate() > 0;
}
}
6. 项目优化方向
完成基础功能后,可以考虑以下扩展点:
6.1 前端优化
- 使用Ajax实现无刷新操作
- 添加数据分页功能
- 引入Bootstrap等UI框架美化界面
6.2 后端优化
- 引入Logback日志框架
- 添加AOP实现统一日志和异常处理
- 使用连接池提升性能
6.3 架构优化
- 将JSP替换为Thymeleaf模板引擎
- 采用三层架构分层开发
- 引入Spring框架简化配置
我在实际开发中发现,部门管理模块虽然简单,但涵盖了企业级应用开发的典型场景。建议初学者在完成基础功能后,尝试将其改造成RESTful风格接口,为后续学习SpringBoot打下基础。
