基于SSH框架的篮球馆场地预订管理系统 - 源码深度解析

JavaJavaScriptSSH框架HTMLCSSMySQLJSP+Servlet
2026-03-184 浏览

文章摘要

本项目是一款基于SSH(Struts2 + Spring + Hibernate)集成框架开发的篮球馆场地预订管理系统,旨在解决传统体育场馆依赖电话或现场登记带来的效率低下、信息不透明和管理混乱等核心痛点。系统通过数字化的场地管理与在线预订功能,为场馆运营方提供清晰的场地状态视图与营收数据,同时为用...

在体育产业数字化浪潮下,传统篮球场馆的运营模式正面临严峻挑战。电话预约的占线拥堵、现场登记的手忙脚乱、场地状态的更新滞后以及财务对账的复杂繁琐,构成了制约场馆服务效率与用户体验提升的核心瓶颈。为解决这些痛点,我们设计并实现了一套基于SSH(Struts2 + Spring + Hibernate)集成框架的篮球场馆智能预订平台——"CourtSync 场馆通"。该系统通过全流程数字化管理,为场馆方提供了高效的运营工具,同时为用户带来了便捷透明的预订体验。

系统采用经典的三层架构设计,各层职责分明,通过框架整合实现了高内聚低耦合的工程目标。表现层由Struts2框架主导,负责接收用户HTTP请求、封装表单数据并控制页面导航。其核心机制是通过配置struts.xml映射文件,将特定的URL请求路由至对应的Action类进行处理。业务逻辑层构建于Spring框架之上,利用其控制反转(IoC)和依赖注入(DI)容器,统一管理Service组件、DAO对象及事务边界。数据持久层则依托Hibernate实现对象关系映射(ORM),将Java实体对象与数据库表结构无缝衔接,极大简化了数据持久化操作。三层之间通过接口抽象进行通信,确保了系统的可测试性与可维护性。

数据库架构设计与核心表解析

数据库作为系统的数据基石,其设计直接决定了系统的性能与稳定性。本系统共设计11张核心数据表,以下重点分析其中三张关键表的结构与设计亮点。

场地信息表(b_court) 是系统的核心资源表,其结构设计体现了对业务细节的精准把握:

CREATE TABLE `b_court` (
  `courtId` int(11) NOT NULL AUTO_INCREMENT,
  `courtName` varchar(50) DEFAULT NULL,
  `area` varchar(50) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  `introduce` text,
  `courtDate` date DEFAULT NULL,
  `state` int(11) DEFAULT '1',
  PRIMARY KEY (`courtId`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

该表设计中,price字段采用decimal(10,2)类型,确保金额计算的精确性,避免浮点数精度问题。state字段使用整型标识场地状态(如1-可用,0-停用),为后续状态扩展预留了空间。courtDate字段独立存储,支持按日期动态调整场地可用性,满足了场馆特殊日期管理的需求。

订单主表(b_order) 的设计展现了复杂业务关系的处理能力:

CREATE TABLE `b_order` (
  `orderId` int(11) NOT NULL AUTO_INCREMENT,
  `orderNo` varchar(100) DEFAULT NULL,
  `userId` int(11) DEFAULT NULL,
  `totalMoney` decimal(10,2) DEFAULT NULL,
  `createTime` datetime DEFAULT NULL,
  `status` int(11) DEFAULT '1',
  `payTime` datetime DEFAULT NULL,
  `payType` int(11) DEFAULT NULL,
  PRIMARY KEY (`orderId`),
  KEY `FK_order_user` (`userId`),
  CONSTRAINT `FK_order_user` FOREIGN KEY (`userId`) REFERENCES `b_user` (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

订单表通过orderNo字段存储唯一订单号,采用业务自定义规则生成,便于追踪查询。status字段完整记录了订单生命周期(待支付、已支付、已完成、已取消等)。外键userId关联用户表,确保了数据引用完整性。payTimepayType的分离设计,支持多种支付方式接入与支付时间记录。

订单明细表(b_order_detail) 采用主从表结构实现复杂订单的灵活管理:

CREATE TABLE `b_order_detail` (
  `detailId` int(11) NOT NULL AUTO_INCREMENT,
  `orderId` int(11) DEFAULT NULL,
  `courtId` int(11) DEFAULT NULL,
  `startTime` datetime DEFAULT NULL,
  `endTime` datetime DEFAULT NULL,
  `total` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`detailId`),
  KEY `FK_detail_order` (`orderId`),
  KEY `FK_detail_court` (`courtId`),
  CONSTRAINT `FK_detail_court` FOREIGN KEY (`courtId`) REFERENCES `b_court` (`courtId`),
  CONSTRAINT `FK_detail_order` FOREIGN KEY (`orderId`) REFERENCES `b_order` (`orderId`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

该表通过startTimeendTime精确记录场地使用时段,为时段冲突检测提供数据基础。与主表的解耦设计支持一个订单同时预订多个场地或时段,满足了团体活动的复杂预订需求。total字段冗余存储明细金额,既提高了查询效率,又确保了历史价格的准确性。

核心功能模块深度解析

1. 智能场地预订与冲突检测机制

场地预订是系统的核心功能,其实现涉及复杂的业务逻辑判断。前端通过JSP页面展示场地日历视图,用户选择日期和时段后,系统需实时检测该时段是否已被预订。

// 场地预订冲突检测核心逻辑
public class CourtBookingService {
    
    public BookingResult bookCourt(BookingRequest request) {
        // 检测时段冲突
        List<OrderDetail> conflicts = orderDetailDao.findConflicts(
            request.getCourtId(), 
            request.getStartTime(), 
            request.getEndTime()
        );
        
        if (!conflicts.isEmpty()) {
            return BookingResult.error("该时段已被预订,请选择其他时段");
        }
        
        // 创建订单
        Order order = new Order();
        order.setOrderNo(generateOrderNo());
        order.setUserId(request.getUserId());
        order.setCreateTime(new Date());
        order.setStatus(OrderStatus.PENDING_PAYMENT);
        
        // 创建订单明细
        OrderDetail detail = new OrderDetail();
        detail.setCourtId(request.getCourtId());
        detail.setStartTime(request.getStartTime());
        detail.setEndTime(request.getEndTime());
        detail.setTotal(calculateAmount(request));
        
        order.getOrderDetails().add(detail);
        order.setTotalMoney(detail.getTotal());
        
        // 保存订单
        orderDao.save(order);
        
        return BookingResult.success(order);
    }
    
    private String generateOrderNo() {
        return "CO" + System.currentTimeMillis() + 
               String.format("%04d", new Random().nextInt(9999));
    }
}

用户预订界面

冲突检测通过HQL查询实现,精确比对时间区间重叠:

@Repository
public class OrderDetailDaoImpl implements OrderDetailDao {
    
    public List<OrderDetail> findConflicts(Integer courtId, Date startTime, Date endTime) {
        String hql = "FROM OrderDetail od WHERE od.courtId = :courtId " +
                    "AND od.status != :cancelledStatus " +
                    "AND ((od.startTime BETWEEN :startTime AND :endTime) " +
                    "OR (od.endTime BETWEEN :startTime AND :endTime) " +
                    "OR (:startTime BETWEEN od.startTime AND od.endTime))";
        
        return getSession().createQuery(hql, OrderDetail.class)
                .setParameter("courtId", courtId)
                .setParameter("cancelledStatus", OrderStatus.CANCELLED)
                .setParameter("startTime", startTime)
                .setParameter("endTime", endTime)
                .list();
    }
}

2. 多角色权限管理与安全控制

系统支持管理员、收银员、普通用户三级角色,各角色权限严格分离。通过Struts2拦截器实现统一的权限验证:

// 权限拦截器实现
public class AuthorizationInterceptor extends AbstractInterceptor {
    
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        ActionContext context = invocation.getInvocationContext();
        HttpSession session = context.getSession();
        
        User user = (User) session.getAttribute("currentUser");
        if (user == null) {
            return "login"; // 跳转到登录页
        }
        
        // 获取请求的Action和Method
        String actionName = invocation.getProxy().getActionName();
        String methodName = invocation.getProxy().getMethod();
        
        // 检查用户权限
        if (!hasPermission(user, actionName, methodName)) {
            return "noPermission"; // 权限不足页面
        }
        
        return invocation.invoke();
    }
    
    private boolean hasPermission(User user, String actionName, String methodName) {
        // 基于角色和权限配置的验证逻辑
        Set<String> permissions = permissionService.getPermissions(user.getRole());
        String requiredPermission = actionName + ":" + methodName;
        
        return permissions.contains(requiredPermission);
    }
}

管理员登录界面

用户登录验证通过Spring Service层实现:

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserDao userDao;
    
    public LoginResult login(String username, String password) {
        User user = userDao.findByUsername(username);
        
        if (user == null) {
            return LoginResult.error("用户不存在");
        }
        
        if (!user.getPassword().equals(md5(password))) {
            return LoginResult.error("密码错误");
        }
        
        if (user.getStatus() != 1) {
            return LoginResult.error("账户已被禁用");
        }
        
        // 登录成功,更新最后登录时间
        user.setLastLoginTime(new Date());
        userDao.update(user);
        
        return LoginResult.success(user);
    }
}

3. 订单管理与支付流程集成

订单管理模块采用Struts2 Action处理前端请求,通过Spring注解管理事务:

// 订单管理Action
@Controller
@Scope("prototype")
public class OrderAction extends BaseAction {
    
    @Autowired
    private OrderService orderService;
    
    private Order order;
    private List<Order> orders;
    
    // 创建订单
    public String create() {
        try {
            order.setUserId(getCurrentUser().getUserId());
            Order result = orderService.createOrder(order);
            setJsonResult(Result.success(result));
        } catch (BusinessException e) {
            setJsonResult(Result.error(e.getMessage()));
        }
        return JSON;
    }
    
    // 查询用户订单
    public String listByUser() {
        Integer userId = getCurrentUser().getUserId();
        orders = orderService.findOrdersByUser(userId);
        return SUCCESS;
    }
    
    // 支付订单
    public String pay() {
        try {
            orderService.payOrder(order.getOrderId(), getCurrentUser());
            setJsonResult(Result.success("支付成功"));
        } catch (BusinessException e) {
            setJsonResult(Result.error(e.getMessage()));
        }
        return JSON;
    }
    
    // Getter和Setter方法
    public Order getOrder() { return order; }
    public void setOrder(Order order) { this.order = order; }
    public List<Order> getOrders() { return orders; }
}

订单管理界面

支付服务通过Spring声明式事务确保数据一致性:

@Service
@Transactional
public class PaymentService {
    
    @Autowired
    private OrderDao orderDao;
    
    @Autowired
    private PaymentRecordDao paymentRecordDao;
    
    public void processPayment(Integer orderId, Integer payType, User user) {
        Order order = orderDao.findById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在");
        }
        
        if (order.getStatus() != OrderStatus.PENDING_PAYMENT) {
            throw new BusinessException("订单状态异常,无法支付");
        }
        
        // 创建支付记录
        PaymentRecord record = new PaymentRecord();
        record.setOrderId(orderId);
        record.setAmount(order.getTotalMoney());
        record.setPayType(payType);
        record.setPayTime(new Date());
        record.setUserId(user.getUserId());
        
        paymentRecordDao.save(record);
        
        // 更新订单状态
        order.setStatus(OrderStatus.PAID);
        order.setPayTime(new Date());
        order.setPayType(payType);
        orderDao.update(order);
        
        // 记录审计日志
        auditService.logPayment(orderId, user.getUserId());
    }
}

4. 场地信息动态管理与可视化展示

场地管理模块支持管理员对场地信息进行全面维护,包括增删改查、状态管理等:

// 场地管理Action
@Controller
@Scope("prototype")
public class CourtAction extends BaseAction {
    
    @Autowired
    private CourtService courtService;
    
    private Court court;
    private List<Court> courts;
    private File uploadImage; // 上传的图片文件
    
    // 保存或更新场地信息
    public String save() {
        try {
            if (uploadImage != null) {
                // 处理图片上传
                String imagePath = fileService.saveImage(uploadImage);
                court.setImagePath(imagePath);
            }
            
            if (court.getCourtId() == null) {
                courtService.addCourt(court);
            } else {
                courtService.updateCourt(court);
            }
            setJsonResult(Result.success("保存成功"));
        } catch (Exception e) {
            setJsonResult(Result.error("保存失败:" + e.getMessage()));
        }
        return JSON;
    }
    
    // 获取场地列表
    public String list() {
        courts = courtService.findAllCourts();
        return SUCCESS;
    }
    
    // 根据条件查询场地
    public String search() {
        CourtCriteria criteria = buildCriteriaFromRequest();
        courts = courtService.findCourtsByCriteria(criteria);
        return SUCCESS;
    }
}

场地管理界面

实体模型与数据持久化设计

系统通过Hibernate实体映射实现对象关系管理,以下是核心实体类的设计:

// 场地实体类
@Entity
@Table(name = "b_court")
public class Court implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "courtId")
    private Integer courtId;
    
    @Column(name = "courtName", length = 50)
    private String courtName;
    
    @Column(name = "area", length = 50)
    private String area;
    
    @Column(name = "price", precision = 10, scale = 2)
    private BigDecimal price;
    
    @Column(name = "introduce", columnDefinition = "text")
    private String introduce;
    
    @Temporal(TemporalType.DATE)
    @Column(name = "courtDate")
    private Date courtDate;
    
    @Column(name = "state")
    private Integer state;
    
    @OneToMany(mappedBy = "court", cascade = CascadeType.ALL)
    private Set<OrderDetail> orderDetails = new HashSet<>();
    
    // 省略getter/setter方法
}

// 订单实体类
@Entity
@Table(name = "b_order")
public class Order implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "orderId")
    private Integer orderId;
    
    @Column(name = "orderNo", length = 100)
    private String orderNo;
    
    @ManyToOne
    @JoinColumn(name = "userId")
    private User user;
    
    @Column(name = "totalMoney", precision = 10, scale = 2)
    private BigDecimal totalMoney;
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "createTime")
    private Date createTime;
    
    @Column(name = "status")
    private Integer status;
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "payTime")
    private Date payTime;
    
    @Column(name = "payType")
    private Integer payType;
    
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<OrderDetail> orderDetails = new HashSet<>();
    
    // 业务逻辑方法
    public boolean isPayable() {
        return OrderStatus.PENDING_PAYMENT.equals(this.status);
    }
    
    public boolean isCancellable() {
        return OrderStatus.PENDING_PAYMENT.equals(this.status) || 
               OrderStatus.PAID.equals(this.status);
    }
}

系统配置与框架整合

SSH框架的整合通过Spring的ApplicationContext统一管理,关键配置如下:

<!-- applicationContext.xml 核心配置 -->
<beans xmlns="http://www.springframework.org/schema/beans">
    
    <!-- 数据源配置 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/basketball_court"/>
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxPoolSize" value="50"/>
        <property name="minPoolSize" value="5"/>
    </bean>
    
    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="com.courtsync.entity"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="transactionManager" 
          class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
本文关键词
SSH框架篮球馆场地预订管理系统源码解析数据库设计

上下篇

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