基于JSP+Servlet的旅游预订管理系统 - 源码深度解析

JavaJavaScriptHTMLCSSMySQLJSP+Servlet
2026-03-052 浏览

文章摘要

本项目是一款基于JSP+Servlet技术栈构建的旅游预订管理系统,旨在为中小型旅行社或旅游服务商提供一个功能完整、稳定可靠的线上业务管理平台。其核心业务价值在于将传统的线下旅游产品预订、客户信息登记及订单处理流程全面数字化,有效解决了手工记录效率低下、订单状态跟踪困难、产品信息更新不及时等核心运营...

在当今旅游业快速数字化的背景下,传统旅行社面临着提升运营效率、优化客户体验的迫切需求。手工处理订单、电话沟通确认、纸质档案管理等方式不仅效率低下,而且容易出错,难以适应现代商业节奏。针对这一市场痛点,采用JSP+Servlet技术栈构建的旅游预订管理系统提供了一个切实可行的解决方案。该系统将旅游产品管理、在线预订、客户服务等核心业务流程进行了数字化整合,为中小型旅游企业实现了业务模式的转型升级。

系统采用经典的J2EE Model 1架构模式,这种架构虽然相对简单,但对于中小型项目的快速开发和维护具有显著优势。JSP页面负责前端视图的渲染和用户交互,Servlet作为控制器处理所有业务逻辑和请求分发,JDBC技术实现与MySQL数据库的持久化操作。这种分层架构确保了代码的可读性和可维护性,为后续功能扩展奠定了良好基础。

数据库架构设计解析

系统的数据模型设计充分考虑了旅游业务的复杂性,通过10个核心数据表的有机组合,完整覆盖了用户管理、产品展示、订单处理等业务场景。其中几个关键表的设计体现了良好的数据库设计原则。

用户信息表(users)的设计体现了完整的安全性和扩展性考量:

CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    phone VARCHAR(20),
    real_name VARCHAR(50),
    id_card VARCHAR(20),
    user_type ENUM('customer', 'admin') DEFAULT 'customer',
    registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_login_time TIMESTAMP NULL,
    status ENUM('active', 'inactive') DEFAULT 'active'
);

该表通过user_type字段实现用户角色区分,支持客户和管理员两种身份。password字段预留了足够的长度以支持加密存储,id_card字段为实名认证提供了数据基础。时间戳字段的设置为用户行为分析提供了数据支持。

旅游产品表(tour_products)的设计展现了业务模型的完整性:

CREATE TABLE tour_products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    product_name VARCHAR(200) NOT NULL,
    description TEXT,
    price DECIMAL(10,2) NOT NULL,
    discount_price DECIMAL(10,2),
    destination VARCHAR(100) NOT NULL,
    duration_days INT NOT NULL,
    start_date DATE NOT NULL,
    end_date DATE NOT NULL,
    max_participants INT NOT NULL,
    current_participants INT DEFAULT 0,
    image_url VARCHAR(500),
    category_id INT,
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    status ENUM('available', 'sold_out', 'cancelled') DEFAULT 'available'
);

该表通过pricediscount_price字段支持灵活的定价策略,max_participantscurrent_participants字段实现了库存控制机制。status字段的三态设计确保了产品状态管理的精确性。

订单表(orders)的设计体现了事务处理的严谨性:

CREATE TABLE orders (
    order_id VARCHAR(32) PRIMARY KEY,
    user_id INT NOT NULL,
    product_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    total_amount DECIMAL(10,2) NOT NULL,
    participant_count INT NOT NULL,
    contact_name VARCHAR(50) NOT NULL,
    contact_phone VARCHAR(20) NOT NULL,
    special_requirements TEXT,
    order_status ENUM('pending', 'confirmed', 'paid', 'completed', 'cancelled') NOT NULL,
    payment_method VARCHAR(20),
    payment_time TIMESTAMP NULL,
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    FOREIGN KEY (product_id) REFERENCES tour_products(product_id)
);

订单表采用五态工作流设计,完整覆盖了从下单到完成的全生命周期。order_id使用32位字符串为主键,为分布式系统扩展预留了空间。外键约束确保了数据的引用完整性。

核心功能模块实现

用户认证与权限管理

系统通过Servlet过滤器实现了统一的权限控制,确保不同角色用户只能访问授权资源。登录验证模块采用Session机制维护用户状态。

// 用户登录验证Servlet核心代码
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        
        UserDAO userDAO = new UserDAO();
        User user = userDAO.authenticate(username, password);
        
        if (user != null) {
            HttpSession session = request.getSession();
            session.setAttribute("currentUser", user);
            session.setMaxInactiveInterval(30 * 60); // 30分钟超时
            
            if ("admin".equals(user.getUserType())) {
                response.sendRedirect("admin/dashboard.jsp");
            } else {
                response.sendRedirect("user/home.jsp");
            }
        } else {
            request.setAttribute("errorMessage", "用户名或密码错误");
            request.getRequestDispatcher("login.jsp").forward(request, response);
        }
    }
}

管理员登录界面

旅游产品管理功能

管理员通过产品管理模块可以实现旅游线路的增删改查操作,系统提供了完整的产品信息维护界面。

// 产品添加Servlet核心逻辑
public class ProductAddServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        try {
            TourProduct product = new TourProduct();
            product.setProductName(request.getParameter("productName"));
            product.setDescription(request.getParameter("description"));
            product.setPrice(new BigDecimal(request.getParameter("price")));
            product.setDestination(request.getParameter("destination"));
            product.setDurationDays(Integer.parseInt(request.getParameter("durationDays")));
            
            ProductDAO productDAO = new ProductDAO();
            boolean success = productDAO.addProduct(product);
            
            if (success) {
                response.sendRedirect("product-management.jsp?message=添加成功");
            } else {
                request.setAttribute("error", "添加失败");
                request.getRequestDispatcher("product-add.jsp").forward(request, response);
            }
        } catch (Exception e) {
            throw new ServletException("产品添加异常", e);
        }
    }
}

景点管理界面

在线预订业务流程

客户预订功能实现了完整的业务逻辑,包括库存检查、价格计算、订单生成等关键环节。

// 订单创建核心业务逻辑
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");
            return;
        }
        
        int productId = Integer.parseInt(request.getParameter("productId"));
        int participantCount = Integer.parseInt(request.getParameter("participantCount"));
        
        try {
            ProductDAO productDAO = new ProductDAO();
            TourProduct product = productDAO.getProductById(productId);
            
            // 库存验证
            if (product.getCurrentParticipants() + participantCount > product.getMaxParticipants()) {
                request.setAttribute("error", "所选产品库存不足");
                request.getRequestDispatcher("product-detail.jsp?id=" + productId).forward(request, response);
                return;
            }
            
            // 价格计算
            BigDecimal unitPrice = product.getDiscountPrice() != null ? 
                product.getDiscountPrice() : product.getPrice();
            BigDecimal totalAmount = unitPrice.multiply(new BigDecimal(participantCount));
            
            // 生成订单
            Order order = new Order();
            order.setOrderId(generateOrderId());
            order.setUserId(user.getUserId());
            order.setProductId(productId);
            order.setTotalAmount(totalAmount);
            order.setParticipantCount(participantCount);
            order.setOrderStatus("pending");
            
            OrderDAO orderDAO = new OrderDAO();
            boolean success = orderDAO.createOrder(order);
            
            if (success) {
                // 更新产品库存
                productDAO.updateParticipantCount(productId, participantCount);
                response.sendRedirect("order-confirm.jsp?orderId=" + order.getOrderId());
            }
        } catch (Exception e) {
            throw new ServletException("预订处理异常", e);
        }
    }
    
    private String generateOrderId() {
        return "ORD" + System.currentTimeMillis() + 
               String.format("%04d", new Random().nextInt(9999));
    }
}

消息管理功能

系统提供了完整的站内消息和留言板功能,支持用户与管理员的双向沟通。

// 消息处理Servlet
public class MessageServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        String action = request.getParameter("action");
        MessageDAO messageDAO = new MessageDAO();
        
        switch (action) {
            case "add":
                Message message = new Message();
                message.setTitle(request.getParameter("title"));
                message.setContent(request.getParameter("content"));
                message.setSenderType(request.getParameter("senderType"));
                message.setCreatedTime(new Timestamp(System.currentTimeMillis()));
                messageDAO.addMessage(message);
                break;
                
            case "delete":
                int messageId = Integer.parseInt(request.getParameter("messageId"));
                messageDAO.deleteMessage(messageId);
                break;
                
            case "reply":
                int parentId = Integer.parseInt(request.getParameter("parentId"));
                String replyContent = request.getParameter("replyContent");
                messageDAO.addReply(parentId, replyContent);
                break;
        }
        
        response.sendRedirect("message-management.jsp");
    }
}

留言管理界面

数据访问层实现

系统采用DAO模式实现数据持久化,通过连接池技术优化数据库访问性能。

// 数据库连接工具类
public class DBUtil {
    private static DataSource dataSource;
    
    static {
        try {
            Context initContext = new InitialContext();
            Context envContext = (Context) initContext.lookup("java:/comp/env");
            dataSource = (DataSource) envContext.lookup("jdbc/tourDB");
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
    
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

// 基础DAO实现
public abstract class BaseDAO {
    protected Connection getConnection() throws SQLException {
        return DBUtil.getConnection();
    }
    
    protected void closeResources(Connection conn, PreparedStatement pstmt, ResultSet rs) {
        try {
            if (rs != null) rs.close();
            if (pstmt != null) pstmt.close();
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

前端界面技术实现

系统前端采用经典的JSP技术结合JavaScript实现动态交互效果。通过EL表达式和JSTL标签库简化页面逻辑。

<%-- 产品列表页面示例 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>旅游产品列表</title>
    <style>
        .product-card {
            border: 1px solid #ddd;
            padding: 15px;
            margin: 10px;
            border-radius: 5px;
        }
        .price {
            color: #e74c3c;
            font-size: 1.2em;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>热门旅游线路</h2>
        
        <c:forEach var="product" items="${productList}">
            <div class="product-card">
                <h3>${product.productName}</h3>
                <p>目的地:${product.destination}</p>
                <p>行程天数:${product.durationDays}天</p>
                <p class="price">
                    <c:if test="${product.discountPrice != null}">
                        <span style="text-decoration: line-through; color: #999;">
                            ¥${product.price}
                        </span>
                        ¥${product.discountPrice}
                    </c:if>
                    <c:if test="${product.discountPrice == null}">
                        ¥${product.price}
                    </c:if>
                </p>
                <a href="product-detail.jsp?id=${product.productId}" class="btn">查看详情</a>
            </div>
        </c:forEach>
    </div>
</body>
</html>

用户首页

系统配置与部署

系统的web.xml配置文件完整定义了Servlet映射、过滤器和初始化参数。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
    <!-- 字符编码过滤器 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.tour.util.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>
    
    <!-- 权限控制过滤器 -->
    <filter>
        <filter-name>AuthFilter</filter-name>
        <filter-class>com.tour.filter.AuthFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AuthFilter</filter-name>
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>
    
    <!-- Servlet配置 -->
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.tour.controller.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>ProductServlet</servlet-name>
        <servlet-class>com.tour.controller.ProductServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ProductServlet</servlet-name>
        <url-pattern>/products</url-pattern>
    </servlet-mapping>
    
    <!-- 会话超时配置 -->
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    
    <!-- 欢迎页面 -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

性能优化策略

系统在数据库查询优化方面采用了多种技术手段,确保在高并发场景下的响应性能。

// 分页查询优化实现
public class ProductDAO extends BaseDAO {
    public List<TourProduct> getProductsByPage(int page, int pageSize, String keyword) {
        List<TourProduct> products = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = getConnection();
            String sql = "SELECT * FROM tour_products WHERE status = 'available' ";
            
            if (keyword != null && !keyword.trim().isEmpty()) {
                sql += "AND (product_name LIKE ? OR destination LIKE ?) ";
            }
            
            sql += "ORDER BY created_time DESC LIMIT ? OFFSET ?";
            
            pstmt = conn.prepareStatement(sql);
            int paramIndex = 1;
            
            if (keyword != null && !keyword.trim().isEmpty()) {
                String likeKeyword = "%" + keyword + "%";
                pstmt.setString(paramIndex++, likeKeyword);
                pstmt.setString(paramIndex++, likeKeyword);
            }
            
            pstmt.setInt(paramIndex++, pageSize);
            pstmt.setInt(paramIndex++, (page - 1) * pageSize);
            
            rs = pstmt.executeQuery();
            
            while (rs.next()) {
                TourProduct product = extractProductFromResultSet(rs);
                products.add(product);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeResources(conn, pstmt, rs);
        }
        
        return products;
    }
    
    public int getProductsCount(String keyword) {
        // 计数查询优化,避免全表扫描
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        int count = 0;
        
        try {
            conn = getConnection();
            String sql = "SELECT COUNT(*) FROM tour_products WHERE status = 'available'";
            
            if (keyword != null && !keyword.trim().isEmpty()) {
                sql += " AND (product_name LIKE ? OR destination LIKE ?)";
            }
            
            pstmt = conn.prepareStatement(sql);
            
            if (keyword != null && !keyword.trim().isEmpty()) {
                String likeKeyword = "%" + keyword + "%";
                pstmt.setString(1, likeKeyword);
                pstmt.setString(2, likeKeyword);
            }
            
            rs = pstmt.executeQuery();
            
            if (rs.next()) {
                count = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeResources(conn, pstmt, rs);
        }
        
        return count;
    }
}

系统安全机制

系统通过多层安全防护确保数据安全和业务可靠性,包括输入验证、SQL注入防护、XSS攻击防范等。

// 安全工具类实现
public class SecurityUtil {
    
    // SQL
本文关键词
JSPServlet旅游预订管理系统源码解析数据库设计

上下篇

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