在传统家政服务行业数字化转型的浪潮中,一个高效、透明的线上连接平台应运而生。该系统采用经典的JSP与Servlet技术栈构建,严格遵循MVC设计模式,为家庭用户与专业服务人员之间搭建了可靠的数字化桥梁。
系统架构与技术栈解析
系统采用典型的三层架构设计,表现层由JSP页面负责,通过JSTL标签库和EL表达式实现数据动态渲染,有效避免了在视图中嵌入Java代码,保证了前后端的分离。控制层核心由Servlet担当,负责接收所有前端请求、进行业务逻辑处理与路由分发。数据持久层则通过JDBC直接操作MySQL数据库,完成各类业务数据的CRUD操作。
这种架构选择的优势在于其成熟稳定、学习曲线平缓,特别适合中小型项目的快速开发与部署。Servlet作为Java EE规范的核心组件,提供了强大的请求处理能力,而JSP则简化了动态页面的编写。整个系统通过web.xml配置Servlet映射,形成了清晰的责任链。
<!-- web.xml 中的Servlet配置示例 -->
<servlet>
<servlet-name>ServiceQueryServlet</servlet-name>
<servlet-class>com.housekeeping.controller.ServiceQueryServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServiceQueryServlet</servlet-name>
<url-pattern>/service/query</url-pattern>
</servlet-mapping>
数据库设计深度剖析
系统共设计10张核心数据表,涵盖了用户管理、服务项目、订单交易等业务模块。其中服务项目表t_service的设计尤为值得关注。
CREATE TABLE t_service (
service_id INT PRIMARY KEY AUTO_INCREMENT,
service_name VARCHAR(100) NOT NULL,
category_id INT NOT NULL,
service_price DECIMAL(10,2) NOT NULL,
service_duration INT COMMENT '服务时长(分钟)',
service_description TEXT,
service_image VARCHAR(200),
service_status ENUM('available', 'unavailable') DEFAULT 'available',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES t_service_category(category_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
该表设计体现了多个优化考虑:使用DECIMAL(10,2)确保价格计算的精确性;service_status枚举类型约束了业务状态的可选值;通过外键约束保证数据一致性;create_time和update_time自动维护时间戳,便于审计和数据分析。
订单表t_order的设计则体现了交易系统的复杂性:
CREATE TABLE t_order (
order_id VARCHAR(32) PRIMARY KEY,
user_id INT NOT NULL,
service_id INT NOT NULL,
employee_id INT,
order_time DATETIME NOT NULL,
service_address VARCHAR(200) NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
order_status ENUM('pending', 'confirmed', 'in_progress', 'completed', 'cancelled') DEFAULT 'pending',
payment_status ENUM('unpaid', 'paid', 'refunded') DEFAULT 'unpaid',
customer_rating TINYINT COMMENT '客户评分1-5',
customer_review TEXT,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES t_user(user_id),
FOREIGN KEY (service_id) REFERENCES t_service(service_id),
FOREIGN KEY (employee_id) REFERENCES t_employee(employee_id)
);
订单状态和支付状态分别使用枚举类型,清晰定义了业务流。客户评分和评价字段的设计支持后续的服务质量分析。订单ID采用32位字符串,为后续集成第三方支付平台预留了扩展空间。
核心功能实现详解
1. 服务项目管理模块
服务项目管理是平台运营的核心,管理员可以通过后台对服务项目进行全面的CRUD操作。系统通过ServiceManagementServlet统一处理服务相关的请求。

服务添加功能的Servlet核心代码:
public class ServiceAddServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String serviceName = request.getParameter("serviceName");
String categoryId = request.getParameter("categoryId");
String price = request.getParameter("price");
String description = request.getParameter("description");
// 数据验证
if (StringUtils.isEmpty(serviceName) || StringUtils.isEmpty(price)) {
request.setAttribute("errorMsg", "服务名称和价格不能为空");
request.getRequestDispatcher("/admin/service/add.jsp").forward(request, response);
return;
}
try {
Service service = new Service();
service.setServiceName(serviceName);
service.setCategoryId(Integer.parseInt(categoryId));
service.setServicePrice(new BigDecimal(price));
service.setServiceDescription(description);
service.setServiceStatus("available");
ServiceDAO serviceDAO = new ServiceDAO();
boolean success = serviceDAO.addService(service);
if (success) {
response.sendRedirect("service-list?msg=add_success");
} else {
request.setAttribute("errorMsg", "添加服务失败");
request.getRequestDispatcher("/admin/service/add.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("errorMsg", "系统错误:" + e.getMessage());
request.getRequestDispatcher("/admin/service/add.jsp").forward(request, response);
}
}
}
2. 在线预约业务流程
用户预约功能涉及复杂的业务逻辑,包括服务选择、时间安排、价格计算等环节。系统通过BookingServlet处理完整的预约流程。

预约处理的核心业务逻辑:
public class BookingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("currentUser");
if (user == null) {
response.sendRedirect("../login.jsp?redirect=booking");
return;
}
String serviceId = request.getParameter("serviceId");
String serviceDate = request.getParameter("serviceDate");
String serviceTime = request.getParameter("serviceTime");
String address = request.getParameter("address");
String specialRequirements = request.getParameter("specialRequirements");
try {
// 验证服务可用性
ServiceDAO serviceDAO = new ServiceDAO();
Service service = serviceDAO.getServiceById(Integer.parseInt(serviceId));
if (service == null || !"available".equals(service.getServiceStatus())) {
request.setAttribute("errorMsg", "所选服务不可用");
request.getRequestDispatcher("/booking.jsp").forward(request, response);
return;
}
// 检查时间冲突
BookingDAO bookingDAO = new BookingDAO();
boolean timeAvailable = bookingDAO.checkTimeAvailability(serviceDate, serviceTime);
if (!timeAvailable) {
request.setAttribute("errorMsg", "该时间段已被预约,请选择其他时间");
request.getRequestDispatcher("/booking.jsp").forward(request, response);
return;
}
// 创建订单
Order order = new Order();
order.setOrderId(generateOrderId());
order.setUserId(user.getUserId());
order.setServiceId(Integer.parseInt(serviceId));
order.setOrderTime(LocalDateTime.parse(serviceDate + " " + serviceTime));
order.setServiceAddress(address);
order.setTotalAmount(service.getServicePrice());
order.setSpecialRequirements(specialRequirements);
boolean success = bookingDAO.createOrder(order);
if (success) {
response.sendRedirect("booking-success?orderId=" + order.getOrderId());
} else {
request.setAttribute("errorMsg", "预约失败,请重试");
request.getRequestDispatcher("/booking.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("errorMsg", "系统错误:" + e.getMessage());
request.getRequestDispatcher("/booking.jsp").forward(request, response);
}
}
private String generateOrderId() {
return "ORD" + System.currentTimeMillis() +
String.format("%04d", new Random().nextInt(10000));
}
}
3. 员工信息管理系统
员工管理模块支持家政服务人员的档案管理、技能标签、排班安排等功能。系统通过EmployeeServlet实现员工数据的动态管理。

员工信息查询的DAO层实现:
public class EmployeeDAO {
private Connection connection;
public EmployeeDAO() {
this.connection = DBUtil.getConnection();
}
public List<Employee> getEmployeesByCriteria(String keyword, String category, String status) {
List<Employee> employees = new ArrayList<>();
StringBuilder sql = new StringBuilder(
"SELECT e.*, GROUP_CONCAT(DISTINCT s.skill_name) as skills " +
"FROM t_employee e " +
"LEFT JOIN t_employee_skill es ON e.employee_id = es.employee_id " +
"LEFT JOIN t_skill s ON es.skill_id = s.skill_id " +
"WHERE 1=1"
);
List<Object> params = new ArrayList<>();
if (StringUtils.isNotEmpty(keyword)) {
sql.append(" AND (e.employee_name LIKE ? OR e.employee_phone LIKE ?)");
params.add("%" + keyword + "%");
params.add("%" + keyword + "%");
}
if (StringUtils.isNotEmpty(category)) {
sql.append(" AND e.category_id = ?");
params.add(Integer.parseInt(category));
}
if (StringUtils.isNotEmpty(status)) {
sql.append(" AND e.employee_status = ?");
params.add(status);
}
sql.append(" GROUP BY e.employee_id ORDER BY e.create_time DESC");
try (PreparedStatement stmt = connection.prepareStatement(sql.toString())) {
for (int i = 0; i < params.size(); i++) {
stmt.setObject(i + 1, params.get(i));
}
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Employee employee = mapResultSetToEmployee(rs);
employee.setSkills(rs.getString("skills"));
employees.add(employee);
}
} catch (SQLException e) {
e.printStackTrace();
}
return employees;
}
private Employee mapResultSetToEmployee(ResultSet rs) throws SQLException {
Employee employee = new Employee();
employee.setEmployeeId(rs.getInt("employee_id"));
employee.setEmployeeName(rs.getString("employee_name"));
employee.setEmployeePhone(rs.getString("employee_phone"));
employee.setEmployeeGender(rs.getString("employee_gender"));
employee.setEmployeeAge(rs.getInt("employee_age"));
employee.setWorkYears(rs.getInt("work_years"));
employee.setEmployeeStatus(rs.getString("employee_status"));
employee.setHourlyRate(rs.getBigDecimal("hourly_rate"));
employee.setCreateTime(rs.getTimestamp("create_time").toLocalDateTime());
return employee;
}
}
4. 系统公告与消息管理
平台通过公告系统向用户推送重要通知,消息管理模块则处理用户与客服之间的沟通。

公告发布功能的业务逻辑:
public class AnnouncementServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String title = request.getParameter("title");
String content = request.getParameter("content");
String priority = request.getParameter("priority");
String expiryDate = request.getParameter("expiryDate");
if (StringUtils.isEmpty(title) || StringUtils.isEmpty(content)) {
request.setAttribute("errorMsg", "标题和内容不能为空");
request.getRequestDispatcher("/admin/announcement/add.jsp").forward(request, response);
return;
}
try {
Announcement announcement = new Announcement();
announcement.setTitle(title);
announcement.setContent(content);
announcement.setPriority(priority);
announcement.setExpiryDate(LocalDate.parse(expiryDate));
announcement.setPublisher("系统管理员");
announcement.setPublishTime(LocalDateTime.now());
announcement.setStatus("active");
AnnouncementDAO announcementDAO = new AnnouncementDAO();
boolean success = announcementDAO.addAnnouncement(announcement);
if (success) {
// 清除缓存,确保前台能立即看到最新公告
request.getServletContext().removeAttribute("latestAnnouncements");
response.sendRedirect("announcement-list?msg=publish_success");
} else {
request.setAttribute("errorMsg", "发布公告失败");
request.getRequestDispatcher("/admin/announcement/add.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("errorMsg", "系统错误:" + e.getMessage());
request.getRequestDispatcher("/admin/announcement/add.jsp").forward(request, response);
}
}
}
实体模型与业务逻辑封装
系统通过精心设计的JavaBean实体类来封装业务数据,每个实体类都对应数据库中的一张表,并包含完整的属性定义和业务方法。
用户实体类的设计:
public class User {
private Integer userId;
private String username;
private String password;
private String realName;
private String phone;
private String email;
private String userType; // 'customer', 'employee', 'admin'
private String status; // 'active', 'inactive'
private LocalDateTime createTime;
private LocalDateTime lastLoginTime;
// 构造方法
public User() {}
public User(String username, String password, String userType) {
this.username = username;
this.password = password;
this.userType = userType;
this.createTime = LocalDateTime.now();
this.status = "active";
}
// Getter和Setter方法
public Integer getUserId() { return userId; }
public void setUserId(Integer userId) { this.userId = userId; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
// 业务方法
public boolean validatePassword(String inputPassword) {
return this.password.equals(hashPassword(inputPassword));
}
private String hashPassword(String plainText) {
// 实际项目中应使用更安全的哈希算法
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(plainText.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("密码加密失败", e);
}
}
public boolean canBookService() {
return "customer".equals(userType) && "active".equals(status);
}
}
数据库连接与事务管理
系统通过工具类统一管理数据库连接,确保资源正确释放,并支持基本的事务处理。
数据库连接工具类:
public class DBUtil {
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/housekeeping_db?useSSL=false&serverTimezone=Asia/Shanghai";
private static final String USERNAME = "root";
private static final String PASSWORD = "password";
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("数据库驱动加载失败");
}
}
public static Connection getConnection() {
try {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("数据库连接失败", e);
}
}
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void closeStatement(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void rollbackTransaction(Connection conn) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
系统安全与数据验证
在用户输入处理方面,系统实施了多层次的数据验证策略,包括前端JavaScript验证、Servlet层验证和数据库约束。
用户注册数据验证示例:
public class UserValidator {
public static ValidationResult validateUserRegistration(String username, String password,
String email, String phone) {
ValidationResult result = new ValidationResult();
// 用户名验证
if (StringUtils.isEmpty(username) || username.length() < 3) {
result.addError("username", "用户名长度至少3个字符");
} else if (!username.matches("^[a-zA-Z0-9_]{3,20}$")) {
result.addError("username", "用户名只能包含字母、数字和下划线");
}
// 密码强度验证
if (StringUtils.isEmpty(password) || password.length() < 6) {
result.addError("password", "密码长度至少6个字符");
} else if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$")) {
result.addError("password", "密码必须包含大小写字母和数字");
}
// 邮箱