基于 Spring Boot + JPA + MySQL 的上门家政系统核心功能示例代码

简介: 这是一个基于Spring Boot + JPA + MySQL的上门家政系统核心示例,涵盖用户、服务人员、服务项目及订单管理四大模块。代码结构清晰,含实体类、Repository、Service、Controller及DTO,支持下单、时间冲突检测、状态流转与评价功能,可快速扩展为完整应用。

以下是一个基于 Spring Boot + JPA + MySQL 的上门家政系统核心功能示例代码,涵盖了用户、服务人员、服务项目、订单管理的典型实现。

项目结构

src/main/java/com/housekeeping/
├── entity/
│   ├── User.java
│   ├── Staff.java
│   ├── ServiceItem.java
│   ├── Order.java
│   └── OrderStatus.java
├── repository/
│   ├── UserRepository.java
│   ├── StaffRepository.java
│   ├── ServiceItemRepository.java
│   └── OrderRepository.java
├── service/
│   ├── OrderService.java
│   └── UserService.java
├── controller/
│   ├── OrderController.java
│   └── UserController.java
├── dto/
│   ├── OrderCreateDTO.java
│   └── OrderResponseDTO.java
└── HousekeepingApplication.java

image.gif

1. Maven 依赖(pom.xml 核心部分)

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

image.gif

2. 实体类

2.1 用户实体(User.java)

package com.housekeeping.entity;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String phone;
    private String address;
    private LocalDateTime createTime;
}

image.gif

2.2 家政人员实体(Staff.java)

package com.housekeeping.entity;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "staff")
public class Staff {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String phone;
    private String skill;        // 擅长服务类型
    private Double rating;       // 平均评分
    private Boolean available;   // 是否可接单
    private LocalDateTime createTime;
}

image.gif

2.3 服务项目实体(ServiceItem.java)

package com.housekeeping.entity;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "service_item")
public class ServiceItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;         // 如:日常保洁、深度保洁
    private String description;
    private Double pricePerHour; // 每小时价格
}

image.gif

2.4 订单状态枚举(OrderStatus.java)

package com.housekeeping.entity;
public enum OrderStatus {
    PENDING,      // 待确认
    CONFIRMED,    // 已确认
    PROCESSING,   // 服务中
    COMPLETED,    // 已完成
    CANCELLED     // 已取消
}

image.gif

2.5 订单实体(Order.java)

package com.housekeeping.entity;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false)
    private Long userId;
    @Column(nullable = false)
    private Long staffId;
    @Column(nullable = false)
    private Long serviceItemId;
    private LocalDateTime serviceStartTime;
    private Integer durationHours;     // 服务时长(小时)
    private Double totalPrice;
    private String address;
    @Enumerated(EnumType.STRING)
    private OrderStatus status;
    private String comment;            // 评价内容
    private Integer rating;            // 评分1-5
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

image.gif

3. Repository 层

package com.housekeeping.repository;
import com.housekeeping.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.time.LocalDateTime;
import java.util.List;
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByUserId(Long userId);
    List<Order> findByStaffId(Long staffId);
    // 查询某家政人员在指定时间段是否有重叠订单
    @Query("SELECT COUNT(o) FROM Order o WHERE o.staffId = :staffId " +
           "AND o.status != 'CANCELLED' " +
           "AND o.serviceStartTime < :endTime " +
           "AND (o.serviceStartTime + (o.durationHours || ' hour') ) > :startTime")
    int countOverlappingOrders(@Param("staffId") Long staffId,
                               @Param("startTime") LocalDateTime startTime,
                               @Param("endTime") LocalDateTime endTime);
}

image.gif

注意:上述 JPA 时间运算依赖数据库方言,实际开发中更推荐使用原生查询或改用 Java 逻辑。此处为演示冲突检测思路。

4. DTO 类

package com.housekeeping.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class OrderCreateDTO {
    private Long userId;
    private Long staffId;
    private Long serviceItemId;
    private LocalDateTime serviceStartTime;
    private Integer durationHours;
    private String address;
}

image.gif

package com.housekeeping.dto;
import lombok.Data;
import com.housekeeping.entity.OrderStatus;
import java.time.LocalDateTime;
@Data
public class OrderResponseDTO {
    private Long id;
    private Long userId;
    private Long staffId;
    private Long serviceItemId;
    private LocalDateTime serviceStartTime;
    private Integer durationHours;
    private Double totalPrice;
    private String address;
    private OrderStatus status;
    private LocalDateTime createTime;
}

image.gif

5. 服务层

5.1 订单服务(OrderService.java)

package com.housekeeping.service;
import com.housekeeping.dto.OrderCreateDTO;
import com.housekeeping.dto.OrderResponseDTO;
import com.housekeeping.entity.*;
import com.housekeeping.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
@RequiredArgsConstructor
public class OrderService {
    private final OrderRepository orderRepository;
    private final UserRepository userRepository;
    private final StaffRepository staffRepository;
    private final ServiceItemRepository serviceItemRepository;
    @Transactional
    public OrderResponseDTO createOrder(OrderCreateDTO dto) {
        // 校验用户、家政人员、服务项目是否存在
        User user = userRepository.findById(dto.getUserId())
                .orElseThrow(() -> new RuntimeException("用户不存在"));
        Staff staff = staffRepository.findById(dto.getStaffId())
                .orElseThrow(() -> new RuntimeException("家政人员不存在"));
        ServiceItem item = serviceItemRepository.findById(dto.getServiceItemId())
                .orElseThrow(() -> new RuntimeException("服务项目不存在"));
        if (!staff.getAvailable()) {
            throw new RuntimeException("该家政人员当前不可接单");
        }
        // 时间冲突检测(简化:通过Java检查重叠)
        LocalDateTime start = dto.getServiceStartTime();
        LocalDateTime end = start.plusHours(dto.getDurationHours());
        boolean conflict = orderRepository.findAll().stream()
                .filter(o -> o.getStaffId().equals(staff.getId()))
                .filter(o -> o.getStatus() != OrderStatus.CANCELLED)
                .anyMatch(o -> {
                    LocalDateTime oStart = o.getServiceStartTime();
                    LocalDateTime oEnd = oStart.plusHours(o.getDurationHours());
                    return start.isBefore(oEnd) && end.isAfter(oStart);
                });
        if (conflict) {
            throw new RuntimeException("该时间段已有其他订单,请重新选择时间");
        }
        // 计算总价
        Double totalPrice = item.getPricePerHour() * dto.getDurationHours();
        Order order = new Order();
        order.setUserId(user.getId());
        order.setStaffId(staff.getId());
        order.setServiceItemId(item.getId());
        order.setServiceStartTime(start);
        order.setDurationHours(dto.getDurationHours());
        order.setTotalPrice(totalPrice);
        order.setAddress(dto.getAddress());
        order.setStatus(OrderStatus.PENDING);
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        Order saved = orderRepository.save(order);
        return convertToDTO(saved);
    }
    @Transactional
    public void cancelOrder(Long orderId, Long userId) {
        Order order = orderRepository.findById(orderId)
                .orElseThrow(() -> new RuntimeException("订单不存在"));
        if (!order.getUserId().equals(userId)) {
            throw new RuntimeException("无权操作此订单");
        }
        if (order.getStatus() != OrderStatus.PENDING) {
            throw new RuntimeException("只有待确认的订单才能取消");
        }
        order.setStatus(OrderStatus.CANCELLED);
        order.setUpdateTime(LocalDateTime.now());
        orderRepository.save(order);
    }
    @Transactional
    public void completeOrder(Long orderId, Long staffId, String comment, Integer rating) {
        Order order = orderRepository.findById(orderId)
                .orElseThrow(() -> new RuntimeException("订单不存在"));
        if (!order.getStaffId().equals(staffId)) {
            throw new RuntimeException("无权操作此订单");
        }
        if (order.getStatus() != OrderStatus.PROCESSING) {
            throw new RuntimeException("只有服务中的订单才能完成");
        }
        order.setStatus(OrderStatus.COMPLETED);
        order.setComment(comment);
        order.setRating(rating);
        order.setUpdateTime(LocalDateTime.now());
        orderRepository.save(order);
    }
    private OrderResponseDTO convertToDTO(Order order) {
        OrderResponseDTO dto = new OrderResponseDTO();
        dto.setId(order.getId());
        dto.setUserId(order.getUserId());
        dto.setStaffId(order.getStaffId());
        dto.setServiceItemId(order.getServiceItemId());
        dto.setServiceStartTime(order.getServiceStartTime());
        dto.setDurationHours(order.getDurationHours());
        dto.setTotalPrice(order.getTotalPrice());
        dto.setAddress(order.getAddress());
        dto.setStatus(order.getStatus());
        dto.setCreateTime(order.getCreateTime());
        return dto;
    }
}

image.gif

6. 控制器层

6.1 订单控制器(OrderController.java)

package com.housekeeping.controller;
import com.housekeeping.dto.OrderCreateDTO;
import com.housekeeping.dto.OrderResponseDTO;
import com.housekeeping.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
    private final OrderService orderService;
    @PostMapping("/create")
    public ResponseEntity<?> createOrder(@RequestBody OrderCreateDTO dto) {
        try {
            OrderResponseDTO order = orderService.createOrder(dto);
            return ResponseEntity.ok(order);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    @PutMapping("/cancel/{orderId}")
    public ResponseEntity<?> cancelOrder(@PathVariable Long orderId, @RequestParam Long userId) {
        try {
            orderService.cancelOrder(orderId, userId);
            return ResponseEntity.ok("订单已取消");
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    @PutMapping("/complete/{orderId}")
    public ResponseEntity<?> completeOrder(@PathVariable Long orderId,
                                           @RequestParam Long staffId,
                                           @RequestParam String comment,
                                           @RequestParam Integer rating) {
        try {
            orderService.completeOrder(orderId, staffId, comment, rating);
            return ResponseEntity.ok("订单已完成并评价");
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
}

image.gif

6.2 用户控制器示例(UserController.java)

package com.housekeeping.controller;
import com.housekeeping.entity.Order;
import com.housekeeping.repository.OrderRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    private final OrderRepository orderRepository;
    @GetMapping("/{userId}/orders")
    public List<Order> getUserOrders(@PathVariable Long userId) {
        return orderRepository.findByUserId(userId);
    }
}

image.gif

7. 配置文件(application.properties)

spring.datasource.url=jdbc:mysql://localhost:3306/housekeeping?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

image.gif

8. 主启动类

package com.housekeeping;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HousekeepingApplication {
    public static void main(String[] args) {
        SpringApplication.run(HousekeepingApplication.class, args);
    }
}

image.gif

9. 初始化测试数据(可选 CommandLineRunner)

@Component
@RequiredArgsConstructor
public class DataInitializer implements CommandLineRunner {
    private final UserRepository userRepository;
    private final StaffRepository staffRepository;
    private final ServiceItemRepository serviceItemRepository;
    @Override
    public void run(String... args) throws Exception {
        if (userRepository.count() == 0) {
            User user = new User();
            user.setName("张三");
            user.setPhone("13800000000");
            user.setAddress("北京市朝阳区xxx");
            user.setCreateTime(LocalDateTime.now());
            userRepository.save(user);
            Staff staff = new Staff();
            staff.setName("李阿姨");
            staff.setPhone("13911111111");
            staff.setSkill("日常保洁、深度保洁");
            staff.setRating(4.9);
            staff.setAvailable(true);
            staff.setCreateTime(LocalDateTime.now());
            staffRepository.save(staff);
            ServiceItem item = new ServiceItem();
            item.setName("日常保洁");
            item.setDescription("全屋基础清洁");
            item.setPricePerHour(50.0);
            serviceItemRepository.save(item);
        }
    }
}

image.gif

核心业务说明

  1. 下单流程:用户选择服务项目、家政人员、上门时间 → 系统校验人员可用性及时间冲突 → 自动计费 → 生成待确认订单。
  2. 时间冲突检测:通过遍历该人员的未取消订单,判断时间区间是否有重叠。
  3. 订单状态流转:PENDING(待确认)→ CONFIRMED(员工确认后)→ PROCESSING(开始服务)→ COMPLETED(完成+评价),或直接 CANCELLED。
  4. 评价体系:订单完成后可填写文字评价和1-5星评分,后续用于展示家政人员平均分。

此示例可直接扩展为完整项目,加入登录认证(JWT/Spring Security)、支付集成服务人员自动分配位置距离排序等高级功能。

相关文章
|
13天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23495 11
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
|
17天前
|
人工智能 缓存 BI
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro,跑完 Skills —— OA 审批、大屏、报表、部署 5 大实战场景后的真实体验 ![](https://oscimg.oschina.net/oscnet/up608d34aeb6bafc47f
5475 20
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
|
18天前
|
人工智能 JSON BI
DeepSeek V4 来了!超越 Claude Sonnet 4.5,赶紧对接 Claude Code 体验一把
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro 的真实体验与避坑记录 本文记录我将 Claude Code 对接 DeepSeek 最新模型(V4Pro)后的真实体验,测试了 Skills 自动化查询和积木报表 AI 建表两个场景——有惊喜,也踩
6539 16
|
7天前
|
人工智能 缓存 Shell
Claude Code 全攻略:命令大全 + 实战工作流(完整版)
Claude Code 是一款运行在终端环境下的 AI 编码助手,能够直接在项目目录中理解代码结构、编辑文件、执行命令、执行开发计划,并支持持久化记忆、上下文压缩、后台任务、多模型切换等专业能力。对于日常开发、项目维护、快速重构、代码审查等场景,它可以大幅减少手动操作、提升编码效率。本文从常用命令、界面模式、核心指令、记忆机制、图片处理、进阶工作流等维度完整说明,帮助开发者快速上手并稳定使用。
1664 3
|
6天前
|
前端开发 API 内存技术
对比claude code等编程cli工具与deepseek v4的适配情况
DeepSeek V4发布后,多家编程工具因未适配其强制要求的`reasoning_content`字段而报错。本文对比Claude Code、GitHub Copilot、Langcli、OpenCode及DeepSeek-TUI等主流工具的兼容性:Claude Code需按官方方式配置;Langcli表现最佳,开箱即用且无报错;Copilot与OpenCode暂未修复问题;DeepSeek-TUI尚处早期阶段。
1130 3
对比claude code等编程cli工具与deepseek v4的适配情况
|
2天前
|
人工智能 BI 持续交付
Claude Code 深度适配 DeepSeek V4-Pro 实测:全场景通关与真实体验报告
在 AI 编程工具日趋主流的今天,Claude Code 凭借强大的任务执行、工具调用与工程化能力,成为开发者与自动化运维的核心效率工具。但随着原生模型账号稳定性问题频发,寻找一套兼容、稳定、能力在线的替代方案变得尤为重要。DeepSeek V4-Pro 作为新一代高性能大模型,提供了完整兼容 Claude 协议的 API 接口,只需简单配置即可无缝驱动 Claude Code,且在任务执行、工具调用、复杂流程处理上表现极为稳定。
838 0
|
1月前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
27256 65
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)