毕业设计实战:基于SpringBoot的在线租房和招聘平台双系统设计与实现全流程指南

31 阅读21分钟

毕业设计实战:基于SpringBoot的在线租房和招聘平台双系统设计与实现全流程指南

在开发“在线租房和招聘平台”毕业设计时,曾因“房屋订单与用户信息脱节”踩过关键坑——初期未在“房屋订单表”与“用户表”“房屋表”间建立完整外键关联,导致房东处理订单时无法查看租客信用记录、平台管理员无法统计房屋出租率,耗费3天重构表结构、补全业务关联逻辑才解决问题📝。基于此次实战经验,本文将系统拆解从需求分析、技术选型、功能实现到测试验收的全流程要点,为同类“平台型”毕设提供可落地的实施指南。

一、需求分析:锚定租房+招聘双业务核心诉求,避免功能混杂

部分同学在开发“双业务平台”时易陷入“功能拼接”误区,比如笔者曾将租房和招聘功能简单堆砌,导致用户体验割裂。通过分析发现两大业务本质都是“供需匹配”,核心逻辑相通,只需做好角色权限划分即可。

1. 核心用户与功能拆解(四角色双业务体系)

系统包含四大角色:平台管理员、房东/企业(供给方)、普通用户(需求方)、租客/求职者(消费方)。前期曾混淆“房东”与“企业”的发布权限,导致逻辑混乱,明确角色边界后系统清晰度显著提升:

平台管理员端(核心管控功能)
  • 双业务统一管理
    • 用户全生命周期管理:审核房东/企业资质(营业执照、身份证明),管理普通用户账号(信用评级、违规处理);
    • 房源与职位审核:审核房屋信息真实性(图片、价格、位置),审核招聘信息合规性(薪资范围、岗位描述);
    • 订单与投递监管:监控租房订单交易安全,监督简历投递流程规范性,处理纠纷投诉;
  • 内容与社区管理
    • 平台资讯发布:发布租房攻略、求职技巧、政策解读等资讯,按类型分类管理;
    • 论坛内容审核:管理租房社区、求职论坛的帖子,删除违规内容,维护社区秩序;
    • 数据统计分析:统计房屋出租率、岗位投递比、用户活跃度等核心指标,生成可视化报表;
  • 系统基础维护:字典数据管理(房屋类型、职位类型、城市区域等),系统参数配置,操作日志审计。
房东/企业端(供给方功能)
  • 房源/职位发布
    • 房屋发布:发布房源信息(标题、图片、位置、户型、价格、设施),设置租赁规则(押几付几、最短租期);
    • 招聘发布:发布职位信息(岗位、薪资、要求、福利),设置招聘流程(笔试→面试→录用);
    • 信息维护:编辑已发布信息,下架过期房源/职位,查看浏览统计;
  • 订单/投递处理
    • 租房订单管理:查看租房申请,与租客沟通,确认订单,管理租期状态;
    • 简历筛选管理:查看投递简历,筛选合适候选人,安排面试,发送录用通知;
    • 评价与反馈:对租客/求职者进行评价,回复用户咨询,处理投诉建议;
  • 个人中心:账户信息维护,交易记录查看,余额提现管理(涉及支付功能可简化)。
普通用户端(需求方基础功能)
  • 双业务浏览与筛选
    • 租房搜索:按位置、价格、户型、标签多维度筛选房源,收藏心仪房屋,查看房源详情;
    • 求职搜索:按岗位、薪资、行业、地点筛选职位,收藏关注职位,查看公司信息;
  • 个人资料管理:基本信息维护,头像设置,联系方式更新;
  • 互动与交流:在房源/职位下留言咨询,在论坛发帖交流,查看系统消息。
租客/求职者端(需求方进阶功能)
  • 租房核心功能
    • 在线看房:查看房源VR/图片(如有),预约线下看房;
    • 租房申请:提交租房申请,填写入住信息,与房东沟通细节;
    • 订单管理:查看租房订单状态(待确认→已确认→租期中→已结束),支付租金(模拟),签订电子合同(简化);
    • 评价与维权:租期结束后评价房东与房屋,申请退租押金,发起纠纷投诉;
  • 求职核心功能
    • 简历管理:创建多份简历(针对不同岗位),编辑简历内容(教育、经历、技能),上传附件简历;
    • 职位申请:一键投递简历,查看投递状态(已投递→已查看→面试邀约→录用),在线沟通;
    • 面试管理:查看面试安排,确认面试时间,查看面试结果;
    • 签约管理:接受录用通知,查看电子offer,确认入职意向。

2. 需求分析避坑要点(双业务平台特殊问题)

  • 业务隔离与融合的平衡:初期将租房和招聘做成两个独立系统,用户体验差。后续调整为“统一入口+业务分区”模式,用户登录后自主切换业务场景,共用个人中心和消息系统;
  • 角色权限的交叉控制:同一用户可能既是租客又是求职者,还可能申请成为房东或企业。设计“角色申请+平台审核”机制,用户可申请多重身份,权限独立管理;
  • 数据模型的通用性设计:发现租房和招聘在“收藏、留言、订单/投递”等行为上高度相似,抽象出通用行为模型,大幅减少重复开发;
  • 绘制双业务流程图:使用DrawIO分别绘制租房业务流(发布→浏览→申请→签约→履约→评价)和招聘业务流(发布→浏览→投递→筛选→面试→录用),对比发现共性环节,设计统一处理模块。

3. 可行性分析:重点论证业务整合可行性

  • 技术可行性:SpringBoot + Vue + MySQL技术栈成熟稳定,关键在于设计合理的微服务或模块化架构。笔者前期尝试单体架构,随着功能增加代码耦合严重,后续调整为“用户中心+租房服务+招聘服务+公共服务”四模块,开发效率提升;
  • 经济可行性:作为毕设项目,开发成本为零。但需考虑系统价值:整合租房和招聘两大高频需求,提升信息匹配效率,具备现实应用潜力;
  • 操作可行性:设计统一导航栏,左侧固定业务切换入口(租房/招聘),右侧为业务专属功能。经测试,用户5分钟内可掌握基本操作,10分钟可完成一次完整租房或求职流程。

二、技术选型:微服务思想指导模块化设计

前期尝试单体架构开发,随着功能增加(16张表,30+接口),代码维护困难。后续引入“微服务思想”,将系统拆分为独立模块,通过统一认证中心协调。

1. 核心技术栈选型说明(模块化架构)

技术组件选型理由模块化应用
SpringBoot 2.7快速构建独立服务,各模块可独立开发测试创建4个SpringBoot子模块:user-service、rental-service、job-service、common-service
Spring Cloud Gateway作为API网关,统一路由请求到各服务配置租房(/rental/)和招聘(/job/)路由规则,实现业务隔离
Spring Security + JWT统一认证授权,支持多角色令牌用户登录后获取JWT令牌,网关验证后转发到对应服务
MySQL 8.0 + 分库思想支持多数据库实例,物理隔离业务数据用户数据、租房数据、招聘数据可部署在不同数据库实例
Redis 6.2缓存热点数据(房源列表、职位列表),会话管理减少数据库压力,提升列表查询性能
Vue 2 + ElementUI前端微服务化,按业务拆分SPA应用创建rental-app和job-app两个前端项目,通过nginx整合
Nginx反向代理,静态资源服务,负载均衡代理前端应用和后端网关,实现前后端分离部署

2. 模块化开发环境搭建

# 项目结构
online-platform/
├── platform-gateway/          # API网关
├── user-service/              # 用户服务
├── rental-service/            # 租房服务
├── job-service/               # 招聘服务
├── common-service/            # 公共服务(字典、文件、消息)
├── frontend-rental/           # 租房前端
├── frontend-job/              # 招聘前端
└── docker-compose.yml         # 容器编排

# 关键配置:application.yml (user-service示例)
spring:
  application:
    name: user-service
  datasource:
    url: jdbc:mysql://localhost:3306/user_db?useSSL=false
    username: root
    password: 123456
  redis:
    host: localhost
    port: 6379
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  # 服务注册发现

# JWT统一配置(common-service)
jwt:
  header: Authorization
  secret: online-platform-secret-key-2023
  expiration: 86400000  # 24小时

三、数据库设计:双业务数据模型分析与优化

两大业务既有独立性又有相似性,数据库设计需兼顾“分离”与“复用”。

1. 核心实体关系分析(16张表逻辑分组)

第一组:用户与身份相关(4表)

  • yonghu (用户表):基础用户信息,与业务解耦
  • fangdong (房东表):扩展用户为房东的专属信息
  • gongsi (企业表):扩展用户为企业的专属信息
  • admin (管理员表):平台管理人员

第二组:租房业务核心(6表)

  • fangwu (房屋表):房源信息,关联fangdong_id
  • fangwu_collection (房屋收藏):用户收藏关系
  • fangwu_commentback (房屋评价):租后评价
  • fangwu_order (房屋订单):交易核心表
  • fangwu_order_flow (订单流水):支付记录(可扩展)
  • fangwu_view_history (浏览历史):用户行为(可扩展)

第三组:招聘业务核心(6表)

  • zhaopin (职位招聘表):职位信息,关联gongsi_id
  • jianli (简历表):用户简历,关联yonghu_id
  • jianli_toudi (简历投递表):投递记录,双外键关联简历和职位
  • zhaopin_collection (职位收藏)
  • zhaopin_liuyan (职位留言)
  • mianshi_invitation (面试邀请表):可扩展

第四组:公共模块(4表)

  • dic (字典表):统一枚举值管理
  • forum (论坛表):支持多角色发帖(用户、房东、企业、管理员)
  • gonggao (平台资讯表):系统公告和资讯
  • system_log (系统日志):操作审计

2. 关键业务表设计优化(实战经验)

房屋订单表深度优化:

-- 原设计问题:缺少租期信息、支付状态、合同信息
-- 优化后设计
CREATE TABLE `fangwu_order` (
  `id` int NOT NULL AUTO_INCREMENT,
  `order_uuid` varchar(64) NOT NULL COMMENT '订单号',
  `fangwu_id` int NOT NULL COMMENT '房屋ID',
  `yonghu_id` int NOT NULL COMMENT '租客ID',
  `fangdong_id` int NOT NULL COMMENT '房东ID',
  `start_date` date NOT NULL COMMENT '起租日期',
  `end_date` date NOT NULL COMMENT '结束日期',
  `month_count` int NOT NULL COMMENT '租赁月数',
  `monthly_rent` decimal(10,2) NOT NULL COMMENT '月租金',
  `total_amount` decimal(10,2) NOT NULL COMMENT '总金额',
  `deposit` decimal(10,2) NOT NULL COMMENT '押金',
  `order_status` tinyint NOT NULL COMMENT '1待支付 2待确认 3租期中 4已完成 5已取消 6纠纷中',
  `pay_status` tinyint NOT NULL COMMENT '支付状态',
  `contract_url` varchar(500) COMMENT '电子合同地址',
  `cancel_reason` varchar(500) COMMENT '取消原因',
  `checkin_time` datetime COMMENT '入住时间',
  `checkout_time` datetime COMMENT '退租时间',
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_order_uuid` (`order_uuid`),
  KEY `idx_fangwu` (`fangwu_id`),
  KEY `idx_yonghu` (`yonghu_id`),
  KEY `idx_fangdong` (`fangdong_id`),
  KEY `idx_status` (`order_status`),
  CONSTRAINT `fk_order_fangwu` FOREIGN KEY (`fangwu_id`) REFERENCES `fangwu` (`id`),
  CONSTRAINT `fk_order_yonghu` FOREIGN KEY (`yonghu_id`) REFERENCES `yonghu` (`id`),
  CONSTRAINT `fk_order_fangdong` FOREIGN KEY (`fangdong_id`) REFERENCES `fangdong` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房屋订单表';

简历投递表状态机设计:

-- 投递状态流转:1已投递 → 2已查看 → 3筛选通过 → 4面试邀请 → 5面试完成 → 6录用 → 7不匹配
CREATE TABLE `jianli_toudi` (
  `id` int NOT NULL AUTO_INCREMENT,
  `jianli_id` int NOT NULL COMMENT '简历ID',
  `zhaopin_id` int NOT NULL COMMENT '职位ID',
  `status` tinyint NOT NULL DEFAULT 1 COMMENT '投递状态',
  `company_view_time` datetime COMMENT '企业查看时间',
  `filter_result` varchar(200) COMMENT '筛选结果备注',
  `interview_time` datetime COMMENT '面试时间',
  `interview_feedback` text COMMENT '面试反馈',
  `offer_status` tinyint COMMENT '录用状态 1待确认 2已接受 3已拒绝',
  `reject_reason` varchar(500) COMMENT '拒绝原因',
  `create_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_jianli_zhaopin` (`jianli_id`, `zhaopin_id`), -- 防止重复投递
  KEY `idx_zhaopin_status` (`zhaopin_id`, `status`),
  KEY `idx_jianli_status` (`jianli_id`, `status`),
  CONSTRAINT `fk_toudi_jianli` FOREIGN KEY (`jianli_id`) REFERENCES `jianli` (`id`),
  CONSTRAINT `fk_toudi_zhaopin` FOREIGN KEY (`zhaopin_id`) REFERENCES `zhaopin` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='简历投递表';

3. 表关联查询实战(复杂业务场景)

-- 场景1:统计房东的房源出租情况
SELECT 
    f.fangdong_id,
    fd.fangdong_name,
    COUNT(DISTINCT f.id) as total_fangwu,
    COUNT(DISTINCT fo.id) as total_orders,
    COUNT(DISTINCT CASE WHEN fo.order_status = 3 THEN fo.id END) as renting_count,
    ROUND(COUNT(DISTINCT fo.id) * 100.0 / COUNT(DISTINCT f.id), 2) as rent_rate,
    AVG(fo.monthly_rent) as avg_rent,
    SUM(fo.total_amount) as total_income
FROM fangwu f
LEFT JOIN fangdong fd ON f.fangdong_id = fd.id
LEFT JOIN fangwu_order fo ON f.id = fo.fangwu_id AND fo.order_status IN (3,4)
WHERE f.fangwu_delete = 0
GROUP BY f.fangdong_id
ORDER BY total_income DESC;

-- 场景2:求职者投递进度跟踪
SELECT 
    jt.id,
    z.zhaopin_name,
    g.gongsi_name,
    z.zhaopin_daiyu,
    jt.status,
    CASE jt.status
        WHEN 1 THEN '已投递'
        WHEN 2 THEN '已查看'
        WHEN 3 THEN '筛选通过'
        WHEN 4 THEN '面试邀请'
        WHEN 5 THEN '面试完成'
        WHEN 6 THEN '录用'
        WHEN 7 THEN '不匹配'
        ELSE '未知'
    END as status_text,
    jt.interview_time,
    jt.offer_status,
    jt.create_time as toudi_time
FROM jianli_toudi jt
JOIN zhaopin z ON jt.zhaopin_id = z.id
JOIN gongsi g ON z.gongsi_id = g.id
WHERE jt.jianli_id = #{jianliId}
ORDER BY jt.create_time DESC;

四、功能实现:双业务核心模块开发策略

由于涉及两大业务,需采取“并行开发+复用组件”策略,优先完成各自核心流程。

1. 租房业务核心:房屋订单全流程管理(必做模块)

技术难点:状态机与并发控制 租房订单涉及多状态流转(待支付→待确认→租期中→已完成),且热门房源可能被多人同时预订,需要解决“超订”问题。

解决方案:

  1. 状态机设计:使用状态模式,定义订单状态流转规则
// 订单状态枚举
public enum OrderStatus {
    PENDING_PAY(1, "待支付"),
    PENDING_CONFIRM(2, "待确认"),
    RENTING(3, "租期中"),
    COMPLETED(4, "已完成"),
    CANCELLED(5, "已取消"),
    DISPUTE(6, "纠纷中");
    
    // 状态流转规则
    private static final Map<OrderStatus, Set<OrderStatus>> TRANSITION_RULES = new HashMap<>();
    static {
        TRANSITION_RULES.put(PENDING_PAY, Set.of(PENDING_CONFIRM, CANCELLED));
        TRANSITION_RULES.put(PENDING_CONFIRM, Set.of(RENTING, CANCELLED));
        TRANSITION_RULES.put(RENTING, Set.of(COMPLETED, DISPUTE));
        // ... 其他规则
    }
    
    public static boolean canTransition(OrderStatus from, OrderStatus to) {
        return TRANSITION_RULES.getOrDefault(from, Collections.emptySet()).contains(to);
    }
}
  1. 并发控制方案:Redis分布式锁 + 数据库乐观锁
@Service
public class FangwuOrderService {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Transactional(rollbackFor = Exception.class)
    public boolean createOrder(CreateOrderDTO dto) {
        String lockKey = "lock:fangwu:" + dto.getFangwuId();
        String lockValue = UUID.randomUUID().toString();
        
        try {
            // 1. Redis分布式锁,防止同一房源被多人同时下单
            Boolean locked = redisTemplate.opsForValue()
                .setIfAbsent(lockKey, lockValue, 30, TimeUnit.SECONDS);
            if (!Boolean.TRUE.equals(locked)) {
                throw new BusinessException("房源正在被其他人预订,请稍后再试");
            }
            
            // 2. 查询房源并检查可租状态
            Fangwu fangwu = fangwuMapper.selectById(dto.getFangwuId());
            if (fangwu == null || fangwu.getFangwuDelete() == 1) {
                throw new BusinessException("房源不存在或已下架");
            }
            
            // 3. 检查房源在租期时间内是否已被预订(时间冲突检查)
            boolean timeConflict = checkTimeConflict(fangwu.getId(), 
                dto.getStartDate(), dto.getEndDate());
            if (timeConflict) {
                throw new BusinessException("所选时间段房源已被预订");
            }
            
            // 4. 创建订单(数据库层面还有唯一约束防止重复)
            FangwuOrder order = new FangwuOrder();
            // ... 设置订单属性
            order.setOrderStatus(OrderStatus.PENDING_PAY.getCode());
            
            // 5. 使用版本号乐观锁
            int rows = fangwuMapper.updateStock(fangwu.getId(), 
                fangwu.getVersion(), fangwu.getVersion() + 1);
            if (rows == 0) {
                throw new OptimisticLockException("房源信息已变更,请刷新后重试");
            }
            
            return orderMapper.insert(order) > 0;
            
        } finally {
            // 释放锁(使用Lua脚本保证原子性)
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                          "return redis.call('del', KEYS[1]) else return 0 end";
            redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
                Collections.singletonList(lockKey), lockValue);
        }
    }
}

页面设计要点

  • 房源详情页:顶部轮播图(房屋照片),中部基本信息卡片,底部地图位置(集成高德/百度地图API),侧边浮动操作栏(收藏、咨询、立即预订);
  • 订单管理页:租客端和房东端视图不同,租客端侧重状态跟踪,房东端侧重批量操作;
  • 电子合同页:使用PDF.js在线预览合同,支持电子签名(简化版可模拟)。

2. 招聘业务核心:简历智能匹配与投递追踪(答辩亮点)

技术难点:简历解析与智能匹配 传统简历投递是海投模式,体验差。需要实现简历解析和岗位智能匹配。

解决方案:

  1. 简历结构化存储:设计简历表时已考虑结构化字段(jianli_types求职意向、jianli_xinzi期望薪资、jianli_xueli学历等),便于匹配;
  2. 基于规则的智能推荐
@Service
public class JobRecommendService {
    
    /**
     * 为求职者推荐职位
     */
    public List<ZhaopinDTO> recommendJobs(Long userId, Integer resumeId) {
        // 1. 获取用户简历
        Jianli resume = jianliMapper.selectById(resumeId);
        if (resume == null) {
            return Collections.emptyList();
        }
        
        // 2. 构建查询条件(基于简历信息)
        Map<String, Object> params = new HashMap<>();
        params.put("jobType", resume.getJianliTypes()); // 求职意向
        params.put("expectedSalary", resume.getJianliXinzi());
        params.put("education", resume.getJianliXueli());
        params.put("userId", userId); // 排除已投递的
        
        // 3. 查询匹配职位(SQL中实现匹配算法)
        List<Zhaopin> jobs = zhaopinMapper.selectRecommendedJobs(params);
        
        // 4. 计算匹配度并排序
        return jobs.stream()
            .map(job -> {
                ZhaopinDTO dto = convertToDTO(job);
                dto.setMatchScore(calculateMatchScore(resume, job));
                return dto;
            })
            .sorted((a, b) -> b.getMatchScore().compareTo(a.getMatchScore()))
            .limit(20) // 最多推荐20个
            .collect(Collectors.toList());
    }
    
    /**
     * 计算简历与职位的匹配度(0-100分)
     */
    private Integer calculateMatchScore(Jianli resume, Zhaopin job) {
        int score = 0;
        
        // 1. 求职意向匹配(30分)
        if (resume.getJianliTypes().equals(job.getZhaopinTypes())) {
            score += 30;
        }
        
        // 2. 薪资匹配(30分)
        if (isSalaryMatch(resume.getJianliXinzi(), job.getZhaopinDaiyu())) {
            score += 30;
        }
        
        // 3. 学历匹配(20分)
        if (isEducationMatch(resume.getJianliXueli(), job.getEducationRequirement())) {
            score += 20;
        }
        
        // 4. 地点匹配(20分)
        if (isLocationMatch(resume.getJianliAddress(), job.getZhaopinAddress())) {
            score += 20;
        }
        
        return Math.min(score, 100);
    }
}
  1. 投递进度可视化
<!-- 投递进度时间线组件 -->
<template>
  <div class="delivery-timeline">
    <el-timeline>
      <el-timeline-item
        v-for="(step, index) in timelineSteps"
        :key="index"
        :timestamp="step.time"
        :type="step.status"
        :icon="step.icon"
      >
        <div class="step-content">
          <div class="step-title">{{ step.title }}</div>
          <div class="step-desc" v-if="step.description">{{ step.description }}</div>
          <div class="step-action" v-if="step.action">
            <el-button size="mini" @click="handleAction(step.action)">
              {{ step.actionText }}
            </el-button>
          </div>
        </div>
      </el-timeline-item>
    </el-timeline>
  </div>
</template>

<script>
export default {
  props: {
    deliveryId: {
      type: Number,
      required: true
    }
  },
  data() {
    return {
      timelineSteps: [
        { 
          title: '简历已投递', 
          time: '2023-10-10 14:30',
          status: 'primary',
          icon: 'el-icon-document'
        },
        { 
          title: '企业已查看', 
          time: '2023-10-11 09:15',
          status: 'success',
          icon: 'el-icon-view'
        },
        { 
          title: '筛选通过', 
          time: '2023-10-12 16:20',
          status: 'success',
          icon: 'el-icon-check'
        },
        { 
          title: '面试邀请', 
          time: '2023-10-13 10:00',
          status: 'warning',
          icon: 'el-icon-chat-dot-round',
          description: '请确认面试时间:2023-10-16 14:00',
          action: 'confirmInterview',
          actionText: '确认参加'
        },
        { 
          title: '等待面试结果', 
          time: '预计2023-10-18',
          status: 'info',
          icon: 'el-icon-time'
        }
      ]
    }
  }
}
</script>

页面设计要点

  • 简历编辑页:分步骤向导(基本信息→教育经历→工作经历→技能证书),实时保存,支持导入Word/PDF简历(解析功能可简化);
  • 职位推荐页:左侧筛选条件,中间职位卡片列表,右侧匹配度指示器;
  • 投递管理页:看板式展示(已投递、面试中、已录用、不合适),支持批量操作。

3. 公共模块:统一用户中心与消息系统(技术亮点)

设计思路:将用户认证、消息通知、文件服务等公共功能抽象为独立服务,供租房和招聘模块调用。

统一认证中心实现

// 1. 多角色统一登录
@PostMapping("/login")
public Result login(@RequestBody LoginDTO loginDTO) {
    // 根据登录标识判断用户类型
    UserType userType = identifyUserType(loginDTO.getUsername());
    
    UserDetails userDetails;
    switch (userType) {
        case ADMIN:
            userDetails = adminDetailsService.loadUserByUsername(loginDTO.getUsername());
            break;
        case FANGDONG:
            userDetails = fangdongDetailsService.loadUserByUsername(loginDTO.getUsername());
            break;
        case GONGSI:
            userDetails = gongsiDetailsService.loadUserByUsername(loginDTO.getUsername());
            break;
        default: // YONGHU
            userDetails = yonghuDetailsService.loadUserByUsername(loginDTO.getUsername());
    }
    
    // 验证密码
    if (!passwordEncoder.matches(loginDTO.getPassword(), userDetails.getPassword())) {
        throw new BadCredentialsException("密码错误");
    }
    
    // 生成JWT令牌(包含用户类型)
    String token = JwtUtil.generateToken(
        userDetails.getUsername(),
        userType.name(),
        additionalClaims
    );
    
    return Result.success("登录成功", new LoginVO(token, userType));
}

// 2. 网关统一鉴权
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        
        // 公开路径放行
        if (isPublicPath(path)) {
            return chain.filter(exchange);
        }
        
        // 获取token
        String token = getToken(exchange);
        if (token == null) {
            return unauthorized(exchange, "未提供认证令牌");
        }
        
        // 验证token
        Claims claims = JwtUtil.parseToken(token);
        if (claims == null) {
            return unauthorized(exchange, "令牌无效或已过期");
        }
        
        // 检查权限(基于路径和用户类型)
        String userType = claims.get("userType", String.class);
        if (!hasPermission(path, userType)) {
            return unauthorized(exchange, "无权访问该资源");
        }
        
        // 将用户信息添加到请求头
        ServerHttpRequest request = exchange.getRequest().mutate()
            .header("X-User-Id", claims.getSubject())
            .header("X-User-Type", userType)
            .build();
        
        return chain.filter(exchange.mutate().request(request).build());
    }
}

统一消息系统设计

-- 消息表设计(支持多种业务消息)
CREATE TABLE `system_message` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` int NOT NULL COMMENT '接收用户ID',
  `user_type` varchar(20) NOT NULL COMMENT '用户类型',
  `title` varchar(200) NOT NULL COMMENT '消息标题',
  `content` text NOT NULL COMMENT '消息内容',
  `msg_type` varchar(50) NOT NULL COMMENT '消息类型:order_created,interview_invite,etc',
  `business_id` int COMMENT '业务ID(如订单ID、投递ID)',
  `business_type` varchar(50) COMMENT '业务类型:rental,job',
  `is_read` tinyint NOT NULL DEFAULT 0 COMMENT '是否已读',
  `read_time` datetime COMMENT '阅读时间',
  `extra_data` json COMMENT '扩展数据',
  `create_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_user` (`user_id`, `user_type`, `is_read`),
  KEY `idx_business` (`business_type`, `business_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统消息表';

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

五、测试验收:双业务交叉测试策略

双业务平台测试复杂度高,需设计交叉测试用例,验证业务隔离和数据一致性。

1. 功能测试:核心交叉场景

测试场景测试步骤预期结果验证要点
用户双重身份操作用户同时申请成为房东和企业账号,分别发布房源和职位两种身份独立操作,数据隔离,权限正确身份切换、数据隔离、权限验证
跨业务消息通知用户既是租客又是求职者,同时收到租房订单确认和面试邀请消息中心正确分类显示,可分别处理消息分类、业务标识、处理跳转
统一支付验证租房支付(模拟)和招聘服务购买(如置顶职位)支付流程一致,资金账户独立结算支付网关、账户隔离、交易记录
数据统计整合平台管理员查看整体数据报表同时展示租房和招聘核心指标,支持对比分析数据聚合、图表展示、业务对比

2. 性能测试:重点关注并发场景

  • 秒杀场景:热门房源上线,多人同时预订;
  • 批量投递:求职者一键投递多个职位;
  • 列表查询:房源/职位列表分页查询,带复杂筛选条件;
  • 消息推送:系统向大量用户发送通知(如新职位提醒)。

使用JMeter模拟测试:

<!-- JMeter测试计划关键配置 -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="房源秒杀测试">
  <intProp name="ThreadGroup.num_threads">100</intProp> <!-- 100并发用户 -->
  <intProp name="ThreadGroup.ramp_time">10</intProp> <!-- 10秒内启动 -->
  <longProp name="ThreadGroup.duration">60</longProp> <!-- 持续60秒 -->
</ThreadGroup>

<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="创建订单请求">
  <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
    <collectionProp name="Arguments.arguments">
      <elementProp name="fangwuId" elementType="HTTPArgument">
        <stringProp name="Argument.value">${热门房源ID}</stringProp>
      </elementProp>
    </collectionProp>
  </elementProp>
  <stringProp name="HTTPSampler.domain">localhost</stringProp>
  <stringProp name="HTTPSampler.port">8080</stringProp>
  <stringProp name="HTTPSampler.protocol">http</stringProp>
  <stringProp name="HTTPSampler.path">/rental/order/create</stringProp>
  <stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>

3. 安全测试:多角色权限验证

  • 垂直越权:普通用户尝试访问管理员接口;
  • 水平越权:用户A尝试操作用户B的数据;
  • 业务交叉越权:租房用户尝试访问招聘管理功能;
  • 接口安全:API接口是否防止SQL注入、XSS攻击。

六、答辩准备:突出“平台化”设计思维

  1. 演示流程设计(7分钟完整演示):

    • 第1分钟:平台概览,展示双业务入口和统一设计风格;
    • 第2-3分钟:租房业务流程演示(发布→浏览→预订→签约→评价);
    • 第4-5分钟:招聘业务流程演示(发布→搜索→投递→面试→录用);
    • 第6分钟:平台管理演示(数据统计、用户管理、内容审核);
    • 第7分钟:技术亮点展示(微服务架构、智能推荐、并发控制)。
  2. 问题准备与应答

    • "为什么将租房和招聘整合到一个平台?"→"两者都是供需匹配平台,用户群体重叠(年轻人),技术架构相似,整合可提升开发效率和用户体验";
    • "系统如何处理业务冲突?"→"采用模块化设计,业务数据物理隔离,通过统一认证中心协调,前台体验整合,后台数据分离";
    • "系统的扩展性如何?"→"微服务架构,可随时增加新业务模块(如二手交易、技能服务),各服务独立部署扩展";
    • "智能匹配算法如何实现?"→"基于规则引擎+标签系统,考虑求职意向、薪资、地点、技能等多维度匹配,后续可引入机器学习优化"。
  3. 文档与展示材料

    • 系统架构图(突出微服务设计);
    • 数据库ER图(标注核心业务表关系);
    • 业务流程图(租房vs招聘对比展示);
    • 核心代码片段(状态机、分布式锁、智能匹配);
    • 性能测试报告(关键指标截图)。

结语

在线租房和招聘平台作为"双业务平台"类毕设,技术挑战在于业务整合与模块化设计。本文基于实际开发经验,总结了关键要点:

核心成功要素

  1. 架构先行:采用微服务思想,即使不实现完整微服务,也要做到模块化设计;
  2. 数据分离:业务核心数据物理或逻辑隔离,避免混杂;
  3. 统一体验:用户中心、消息系统、支付流程等公共服务统一设计;
  4. **复用思维