基于JSP+Servlet的在线家政服务预约平台 - 源码深度解析

JavaJavaScriptHTMLCSSMySQLJSP+Servlet
2026-03-053 浏览

文章摘要

本项目是一款基于JSP与Servlet技术构建的在线家政服务预约平台,旨在为家庭用户与专业服务人员之间搭建一个高效、透明的数字化连接桥梁。其核心业务价值在于解决了传统家政服务信息不透明、预约流程繁琐、服务匹配效率低下的行业痛点。通过线上集中展示标准化的服务项目、明确的服务报价与人员资质,平台有效降低...

在传统家政服务行业数字化转型的浪潮中,一个高效、透明的线上连接平台应运而生。该系统采用经典的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_timeupdate_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", "密码必须包含大小写字母和数字");
        }
        
        // 邮箱
本文关键词
JSPServlet在线家政服务预约平台源码解析

上下篇

上一篇
没有更多文章
下一篇
没有更多文章