Java全栈项目-大学生租房管理系统(1)

引言

随着高校扩招和城市化进程的加速,大学生校外租房需求日益增长。然而,传统租房市场存在信息不对称、租赁流程繁琐、安全保障不足等问题。本文介绍一个基于Java全栈技术的大学生租房管理系统,旨在为大学生提供便捷、安全、高效的租房服务平台。

系统概述

大学生租房管理系统是一个面向高校学生、房东和管理员的综合性租房服务平台。该系统采用前后端分离架构,前端使用Vue.js框架,后端基于Spring Boot + MyBatis构建,数据库采用MySQL,实现了房源信息管理、用户认证、在线签约、租金支付、投诉处理等核心功能。

技术栈

前端技术

  • Vue.js: 构建用户界面
  • Element UI: 组件库
  • Axios: HTTP客户端
  • Vuex: 状态管理
  • Vue Router: 前端路由

后端技术

  • Spring Boot: 简化Spring应用开发
  • Spring Security: 认证和授权
  • MyBatis: ORM框架
  • Redis: 缓存
  • JWT: 用户认证
  • Swagger: API文档

数据库

  • MySQL: 关系型数据库
  • Druid: 数据库连接池

开发工具

  • IntelliJ IDEA: Java开发IDE
  • VS Code: 前端开发IDE
  • Maven: 项目管理工具
  • Git: 版本控制
  • Docker: 容器化部署

系统架构

系统采用经典的三层架构:

  1. 表现层:Vue.js构建的前端界面
  2. 业务逻辑层:Spring Boot实现的后端服务
  3. 数据访问层:MyBatis + MySQL实现的数据持久化

同时,系统还集成了以下中间件:

  • Redis:用于缓存热点数据,提高系统响应速度
  • Nginx:实现负载均衡和静态资源服务
  • RabbitMQ:处理异步消息,如通知、邮件发送等

核心功能模块

1. 用户管理模块

  • 用户注册与登录
  • 身份认证(学生认证、房东认证)
  • 个人信息管理
  • 角色权限控制

2. 房源管理模块

  • 房源信息发布
  • 房源搜索与筛选
  • 房源详情展示
  • 收藏与比较

3. 预约看房模块

  • 在线预约
  • 预约日程管理
  • 看房反馈
  • 房源评价

数据库设计

系统的核心数据表包括:

  1. 用户表(user):存储用户基本信息
  2. 学生认证表(student_verification):存储学生认证信息
  3. 房东表(landlord):存储房东信息
  4. 房源表(house):存储房源基本信息
  5. 房源详情表(house_detail):存储房源详细信息
  6. 房源图片表(house_image):存储房源图片
  7. 预约表(appointment):存储看房预约信息
  8. 合同表(contract):存储租赁合同信息
  9. 支付表(payment):存储支付记录
  10. 维修表(maintenance):存储维修记录
  11. 评价表(review):存储用户评价
  12. 消息表(message):存储系统消息

核心表结构示例

-- 用户表
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) NOT NULL COMMENT '密码',
  `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
  `id_card` varchar(18) DEFAULT NULL COMMENT '身份证号',
  `phone` varchar(11) NOT NULL COMMENT '手机号',
  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
  `avatar` varchar(255) DEFAULT NULL COMMENT '头像',
  `gender` tinyint(1) DEFAULT NULL COMMENT '性别:0-女,1-男',
  `role` varchar(20) NOT NULL COMMENT '角色:STUDENT-学生,LANDLORD-房东,ADMIN-管理员',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0-禁用,1-正常',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`),
  UNIQUE KEY `uk_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 房源表
CREATE TABLE `house` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `landlord_id` bigint(20) NOT NULL COMMENT '房东ID',
  `title` varchar(100) NOT NULL COMMENT '标题',
  `address` varchar(255) NOT NULL COMMENT '地址',
  `area` decimal(10,2) NOT NULL COMMENT '面积(平方米)',
  `price` decimal(10,2) NOT NULL COMMENT '月租金',
  `deposit` decimal(10,2) NOT NULL COMMENT '押金',
  `house_type` varchar(50) NOT NULL COMMENT '户型',
  `orientation` varchar(20) DEFAULT NULL COMMENT '朝向',
  `floor` varchar(20) DEFAULT NULL COMMENT '楼层',
  `has_elevator` tinyint(1) DEFAULT NULL COMMENT '是否有电梯',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0-下架,1-上架',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_landlord_id` (`landlord_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房源表';

接口设计

系统API接口采用RESTful风格设计,主要包括以下几类:

用户接口

  • POST /api/auth/register:用户注册
  • POST /api/auth/login:用户登录
  • GET /api/users/current:获取当前用户信息
  • PUT /api/users/{id}:更新用户信息
  • POST /api/students/verify:学生认证

房源接口

  • POST /api/houses:发布房源
  • GET /api/houses:查询房源列表
  • GET /api/houses/{id}:获取房源详情
  • PUT /api/houses/{id}:更新房源信息
  • DELETE /api/houses/{id}:删除房源

预约接口

  • POST /api/appointments:创建预约
  • GET /api/appointments:查询预约列表
  • PUT /api/appointments/{id}:更新预约状态
  • DELETE /api/appointments/{id}:取消预约

合同接口

  • POST /api/contracts:创建合同
  • GET /api/contracts:查询合同列表
  • GET /api/contracts/{id}:获取合同详情
  • PUT /api/contracts/{id}:更新合同状态

支付接口

  • POST /api/payments:创建支付
  • GET /api/payments:查询支付记录
  • GET /api/payments/{id}:获取支付详情

系统实现

前端实现

前端基于Vue.js框架实现,主要页面包括:

  1. 首页:展示系统概览、热门房源、最新公告等
  2. 房源列表页:展示房源列表,提供筛选和排序功能
  3. 房源详情页:展示房源详细信息,提供预约功能
  4. 个人中心:管理个人信息、预约、合同等
  5. 后台管理:提供系统管理功能

后端实现

后端基于Spring Boot实现,主要包括以下几个层次:

  1. Controller层:处理HTTP请求,返回响应
  2. Service层:实现业务逻辑
  3. DAO层:实现数据访问
  4. Entity层:定义数据实体
  5. DTO层:定义数据传输对象
  6. Util层:提供工具类

安全实现

系统安全主要通过以下几个方面实现:

  1. 用户认证:基于JWT实现无状态认证
  2. 权限控制:基于RBAC模型实现权限管理
  3. 数据加密:敏感数据加密存储
  4. 防SQL注入:使用参数化查询
  5. 防XSS攻击:输入输出过滤
  6. HTTPS:传输层加密

系统部署

系统采用Docker容器化部署,主要包括以下几个容器:

  1. 前端容器:部署Vue.js应用
  2. 后端容器:部署Spring Boot应用
  3. MySQL容器:部署数据库
  4. Redis容器:部署缓存
  5. Nginx容器:部署反向代理

部署架构图如下:

                    ┌─────────────┐
                    │    Nginx    │
                    └─────────────┘
                           │
              ┌────────────┴────────────┐
              │                         │
      ┌───────▼──────┐         ┌───────▼──────┐
      │  Frontend    │         │   Backend    │
      │  (Vue.js)    │         │ (Spring Boot)│
      └───────┬──────┘         └───────┬──────┘
              │                         │
              │                ┌────────┴────────┐
              │                │                 │
      ┌───────▼──────┐  ┌──────▼─────┐   ┌──────▼─────┐
      │   Browser    │  │   MySQL    │   │   Redis    │
      └──────────────┘  └────────────┘   └────────────┘

系统测试

系统测试主要包括以下几个方面:

  1. 单元测试:使用JUnit测试各个组件
  2. 集成测试:测试组件之间的交互
  3. 接口测试:使用Postman测试API接口
  4. 性能测试:使用JMeter测试系统性能
  5. 安全测试:进行渗透测试和安全扫描

项目亮点

  1. 前后端分离架构:提高开发效率和系统可维护性
  2. 微服务设计思想:模块化设计,便于扩展
  3. 响应式设计:适配不同终端设备
  4. 实时通信:基于WebSocket实现实时消息推送
  5. 数据可视化:直观展示系统运营数据
  6. 智能推荐:基于用户行为推荐合适房源

项目难点及解决方案

1. 高并发处理

  • 问题:节假日期间,系统面临高并发访问压力
  • 解决方案
    • 使用Redis缓存热点数据
    • 实现接口限流
    • 采用异步处理非核心业务
    • 数据库读写分离

2. 数据一致性

  • 问题:支付过程中的数据一致性问题
  • 解决方案
    • 采用分布式事务
    • 实现补偿机制
    • 引入消息队列

3. 安全问题

  • 问题:用户敏感信息保护
  • 解决方案
    • 数据脱敏存储
    • 传输加密
    • 权限精细化控制

系统优化

1. 性能优化

  • 数据库索引优化
  • SQL语句优化
  • JVM参数调优
  • 前端资源压缩与CDN加速

2. 用户体验优化

  • 页面加载速度优化
  • 表单交互优化
  • 响应式布局优化
  • 操作流程简化

未来展望

  1. 移动端应用:开发Android和iOS原生应用
  2. 智能推荐系统:基于机器学习的房源推荐
  3. VR看房:实现虚拟现实看房体验
  4. 区块链合同:基于区块链技术的智能合约
  5. 大数据分析:深度挖掘租房市场数据

总结

大学生租房管理系统是一个综合性的Java全栈项目,涵盖了前端开发、后端开发、数据库设计、系统架构等多个方面。通过该项目,不仅能够解决大学生租房过程中的实际问题,还能够全面提升开发者的技术能力和项目经验。

本项目采用主流的Java全栈技术栈,具有良好的可扩展性和可维护性,为后续功能迭代和系统优化提供了坚实的基础。同时,项目中涉及的高并发处理、数据一致性、安全防护等技术难点,也为开发者提供了宝贵的实践经验。

代码:

Directory Content Summary

Generated at: 2025-02-27 12:58:48

Source Directory: ./rental-system

Directory Structure

rental-system/
  backend/
    pom.xml
    src/
      main/
        java/
          com/
            rental/
              RentalApplication.java
              RentalSystemApplication.java
              config/
                SecurityConfig.java
                WebMvcConfig.java
              controller/
                AppointmentController.java
                FavoriteController.java
                HouseController.java
                HouseReviewController.java
                ReviewReplyController.java
                UserController.java
                VerificationController.java
                ViewingFeedbackController.java
              dao/
                AppointmentDao.java
                ComparisonDao.java
                FavoriteDao.java
                HouseDao.java
                HouseDetailDao.java
                HouseImageDao.java
                HouseReviewDao.java
                LandlordVerificationDao.java
                PermissionDao.java
                ReviewReplyDao.java
                RoleDao.java
                StudentVerificationDao.java
                UserDao.java
                ViewingFeedbackDao.java
              dto/
                AppointmentDTO.java
                FeedbackDTO.java
                HouseDetailDTO.java
                HouseDTO.java
                HouseSearchDTO.java
                LandlordVerificationDTO.java
                LoginDTO.java
                PageResult.java
                RegisterDTO.java
                ReplyDTO.java
                Result.java
                ReviewDTO.java
                StudentVerificationDTO.java
                UserDTO.java
              entity/
                Appointment.java
                Comparison.java
                Favorite.java
                House.java
                HouseDetail.java
                HouseImage.java
                HouseReview.java
                LandlordVerification.java
                Permission.java
                ReviewReply.java
                Role.java
                StudentVerification.java
                User.java
                ViewingFeedback.java
              exception/
                BusinessException.java
                GlobalExceptionHandler.java
                UnauthorizedException.java
              interceptor/
                AuthenticationInterceptor.java
                AuthInterceptor.java
              service/
                AppointmentService.java
                FavoriteService.java
                HouseReviewService.java
                HouseService.java
                ReviewReplyService.java
                UserService.java
                VerificationService.java
                ViewingFeedbackService.java
                impl/
                  AppointmentServiceImpl.java
                  FavoriteServiceImpl.java
                  HouseReviewServiceImpl.java
                  HouseServiceImpl.java
                  ReviewReplyServiceImpl.java
                  UserServiceImpl.java
                  VerificationServiceImpl.java
                  ViewingFeedbackServiceImpl.java
              util/
                JsonUtil.java
                JwtUtil.java
                PasswordEncoder.java
                PasswordUtil.java
        resources/
          application.properties
          application.yml
          schema.sql
          mapper/
            AppointmentMapper.xml
            HouseDetailMapper.xml
            HouseMapper.xml
            HouseReviewMapper.xml
            ReviewReplyMapper.xml
            UserMapper.xml
            ViewingFeedbackMapper.xml
          sql/
            appointment_module.sql
    target/
      classes/
        application.properties
        application.yml
        schema.sql
        com/
          rental/
            config/
            controller/
            dao/
            dto/
            entity/
            exception/
            interceptor/
            service/
              impl/
            util/
        mapper/
          AppointmentMapper.xml
          HouseDetailMapper.xml
          HouseMapper.xml
          HouseReviewMapper.xml
          ReviewReplyMapper.xml
          UserMapper.xml
          ViewingFeedbackMapper.xml
        sql/
          appointment_module.sql
      generated-sources/
        annotations/
      generated-test-sources/
        test-annotations/
      test-classes/
  frontend/
    package.json
    src/
      App.vue
      main.js
      api/
        appointment.js
        favorite.js
        feedback.js
        house.js
        review.js
        user.js
        verification.js
      assets/
        css/
          global.css
      router/
        index.js
        modules/
          appointment.js
      store/
        index.js
        modules/
          appointment.js
      utils/
        auth.js
        date.js
        request.js
      views/
        Home.vue
        Login.vue
        Register.vue
        admin/
          Dashboard.vue
        appointment/
          AppointmentCalendar.vue
          AppointmentDetail.vue
          AppointmentDetail.vue (continuation)
          AppointmentForm.vue
          AppointmentList.vue
        house/
          Detail.vue
          components/
            HouseFeedbacks.vue
            HouseReviews.vue
        user/
          Favorite.vue
          Profile.vue
        verification/
          StudentVerification.vue
  sql/
    01_create_tables.sql
    02_init_data.sql

File Contents

backend\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.rental</groupId>
    <artifactId>rental-system</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rental-system</name>
    <description>College Student Rental Housing Management System</description>
    <properties>
        <java.version>1.8</java.version>
        <mybatis.version>2.2.2</mybatis.version>
        <druid.version>1.2.8</druid.version>
        <jwt.version>0.9.1</jwt.version>
        <swagger.version>3.0.0</swagger.version>
        <fastjson.version>2.0.12</fastjson.version>
        <commons-lang3.version>3.12.0</commons-lang3.version>
        <commons-io.version>2.11.0</commons-io.version>
        <commons-fileupload.version>1.4</commons-fileupload.version>
    </properties>
    <dependencies>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- Druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        
        <!-- JWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jwt.version}</version>
        </dependency>
        
        <!-- Swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        
        <!-- FastJSON -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        
        <!-- Commons -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>${commons-fileupload.version}</version>
        </dependency>
        
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

backend\src\main\java\com\rental\RentalApplication.java

package com.rental;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 租房管理系统启动类
 */
@SpringBootApplication
@EnableTransactionManagement
public class RentalApplication {

    public static void main(String[] args) {
        SpringApplication.run(RentalApplication.class, args);
    }
}
Security Configuration

backend\src\main\java\com\rental\RentalSystemApplication.java

package com.rental;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 大学生租房管理系统启动类
 */
@SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.rental.dao")
public class RentalSystemApplication {

    public static void main(String[] args) {
        SpringApplication.run(RentalSystemApplication.class, args);
    }
}

backend\src\main\java\com\rental\config\SecurityConfig.java

package com.rental.config;

import com.rental.interceptor.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 安全配置
 */
@Configuration
public class SecurityConfig implements WebMvcConfigurer {

    /**
     * 注册拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册认证拦截器
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login", "/user/register", "/house/list", "/house/search", "/house/detail/**");
    }

    /**
     * 跨域配置
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .maxAge(3600);
    }

    /**
     * 认证拦截器
     */
    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}
Authentication Interceptor

backend\src\main\java\com\rental\config\WebMvcConfig.java

package com.rental.config;

import com.rental.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Web配置
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    /**
     * 添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/user/login", "/api/user/register");
    }

    /**
     * 跨域配置
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

backend\src\main\java\com\rental\controller\AppointmentController.java

package com.rental.controller;

import com.rental.dto.AppointmentDTO;
import com.rental.entity.Appointment;
import com.rental.dto.Result;
import com.rental.service.AppointmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 预约控制器
 */
@RestController
@RequestMapping("/appointment")
public class AppointmentController {

    @Autowired
    private AppointmentService appointmentService;

    /**
     * 创建预约
     */
    @PostMapping("/create")
    public Result<Appointment> createAppointment(@RequestBody @Valid AppointmentDTO appointmentDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.createAppointment(appointmentDTO, userId);
    }

    /**
     * 确认预约
     */
    @PostMapping("/confirm/{id}")
    public Result<Void> confirmAppointment(@PathVariable("id") Long appointmentId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.confirmAppointment(appointmentId, userId);
    }

    /**
     * 取消预约
     */
    @PostMapping("/cancel/{id}")
    public Result<Void> cancelAppointment(@PathVariable("id") Long appointmentId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.cancelAppointment(appointmentId, userId);
    }

    /**
     * 完成预约
     */
    @PostMapping("/complete/{id}")
    public Result<Void> completeAppointment(@PathVariable("id") Long appointmentId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.completeAppointment(appointmentId, userId);
    }

    /**
     * 获取预约详情
     */
    @GetMapping("/detail/{id}")
    public Result<Appointment> getAppointmentDetail(@PathVariable("id") Long appointmentId) {
        return appointmentService.getAppointmentById(appointmentId);
    }

    /**
     * 获取用户的预约列表
     */
    @GetMapping("/user")
    public Result<List<Appointment>> getUserAppointments(HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.getUserAppointments(userId);
    }

    /**
     * 获取房东的预约列表
     */
    @GetMapping("/landlord")
    public Result<List<Appointment>> getLandlordAppointments(HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.getLandlordAppointments(userId);
    }

    /**
     * 获取房源的预约列表
     */
    @GetMapping("/house/{houseId}")
    public Result<List<Appointment>> getHouseAppointments(@PathVariable("houseId") Long houseId) {
        return appointmentService.getHouseAppointments(houseId);
    }

    /**
     * 获取指定日期范围内的预约
     */
    @GetMapping("/date-range")
    public Result<List<Appointment>> getAppointmentsByDateRange(
            @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
            HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.getAppointmentsByDateRange(startDate, endDate, userId);
    }

    /**
     * 获取预约统计数据
     */
    @GetMapping("/statistics")
    public Result<Map<String, Object>> getAppointmentStatistics(HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return appointmentService.getAppointmentStatistics(userId);
    }
}

backend\src\main\java\com\rental\controller\FavoriteController.java

package com.rental.controller;

import com.rental.dto.HouseDTO;
import com.rental.dto.Result;
import com.rental.service.FavoriteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 收藏控制器
 */
@RestController
@RequestMapping("/api/favorite")
public class FavoriteController {

    @Autowired
    private FavoriteService favoriteService;

    /**
     * 添加收藏
     */
    @PostMapping("/{userId}/{houseId}")
    public Result<Boolean> addFavorite(@PathVariable Long userId, @PathVariable Long houseId) {
        boolean result = favoriteService.addFavorite(userId, houseId);
        return Result.success(result);
    }

    /**
     * 取消收藏
     */
    @DeleteMapping("/{userId}/{houseId}")
    public Result<Boolean> cancelFavorite(@PathVariable Long userId, @PathVariable Long houseId) {
        boolean result = favoriteService.cancelFavorite(userId, houseId);
        return Result.success(result);
    }

    /**
     * 查询是否收藏
     */
    @GetMapping("/{userId}/{houseId}")
    public Result<Boolean> isFavorite(@PathVariable Long userId, @PathVariable Long houseId) {
        boolean result = favoriteService.isFavorite(userId, houseId);
        return Result.success(result);
    }

    /**
     * 获取收藏列表
     */
    @GetMapping("/list/{userId}")
    public Result<List<HouseDTO>> getFavoriteList(@PathVariable Long userId) {
        List<HouseDTO> favoriteList = favoriteService.getFavoriteList(userId);
        return Result.success(favoriteList);
    }
}

backend\src\main\java\com\rental\controller\HouseController.java

package com.rental.controller;

import com.rental.dto.HouseDTO;
import com.rental.dto.HouseSearchDTO;
import com.rental.dto.PageResult;
import com.rental.dto.Result;
import com.rental.entity.House;
import com.rental.service.HouseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 房源控制器
 */
@RestController
@RequestMapping("/api/house")
public class HouseController {

    @Autowired
    private HouseService houseService;

    /**
     * 获取房源详情
     */
    @GetMapping("/{id}")
    public Result<HouseDTO> getHouseDetail(@PathVariable Long id) {
        HouseDTO houseDTO = houseService.getHouseById(id);
        if (houseDTO == null) {
            return Result.error("房源不存在");
        }
        return Result.success(houseDTO);
    }

    /**
     * 获取房东的房源列表
     */
    @GetMapping("/landlord/{landlordId}")
    public Result<List<HouseDTO>> getLandlordHouseList(@PathVariable Long landlordId) {
        List<HouseDTO> houseList = houseService.getHouseListByLandlordId(landlordId);
        return Result.success(houseList);
    }

    /**
     * 搜索房源
     */
    @PostMapping("/search")
    public Result<PageResult<HouseDTO>> searchHouse(@RequestBody HouseSearchDTO searchDTO) {
        PageResult<HouseDTO> pageResult = houseService.searchHouse(searchDTO);
        return Result.success(pageResult);
    }

    /**
     * 发布房源
     */
    @PostMapping
    public Result<Long> addHouse(@RequestBody @Valid HouseDTO houseDTO) {
        Long houseId = houseService.addHouse(houseDTO);
        return Result.success(houseId);
    }

    /**
     * 更新房源
     */
    @PutMapping
    public Result<Boolean> updateHouse(@RequestBody @Valid HouseDTO houseDTO) {
        boolean result = houseService.updateHouse(houseDTO);
        return Result.success(result);
    }

    /**
     * 删除房源
     */
    @DeleteMapping("/{id}")
    public Result<Boolean> deleteHouse(@PathVariable Long id) {
        boolean result = houseService.deleteHouse(id);
        return Result.success(result);
    }

    /**
     * 批量删除房源
     */
    @DeleteMapping("/batch")
    public Result<Boolean> deleteHouseBatch(@RequestBody Long[] ids) {
        boolean result = houseService.deleteHouseBatch(ids);
        return Result.success(result);
    }

    /**
     * 更新房源状态
     */
    @PutMapping("/{id}/status/{status}")
    public Result<Boolean> updateHouseStatus(@PathVariable Long id, @PathVariable Integer status) {
        boolean result = houseService.updateHouseStatus(id, status);
        return Result.success(result);
    }

    /**
     * 获取房源列表
     */
    @GetMapping("/list")
    public Result<List<HouseDTO>> getHouseList(House house) {
        List<HouseDTO> houseList = houseService.getHouseList(house);
        return Result.success(houseList);
    }
}

backend\src\main\java\com\rental\controller\HouseReviewController.java

package com.rental.controller;

import com.rental.dto.ReviewDTO;
import com.rental.entity.HouseReview;
import com.rental.dto.Result;
import com.rental.service.HouseReviewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;

/**
 * 房源评价控制器
 */
@RestController
@RequestMapping("/review")
public class HouseReviewController {

    @Autowired
    private HouseReviewService houseReviewService;

    /**
     * 提交房源评价
     */
    @PostMapping("/submit")
    public Result<HouseReview> submitReview(@RequestBody @Valid ReviewDTO reviewDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return houseReviewService.submitReview(reviewDTO, userId);
    }

    /**
     * 更新房源评价
     */
    @PutMapping("/update/{id}")
    public Result<Void> updateReview(@PathVariable("id") Long reviewId, @RequestBody @Valid ReviewDTO reviewDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return houseReviewService.updateReview(reviewId, reviewDTO, userId);
    }

    /**
     * 删除房源评价
     */
    @DeleteMapping("/delete/{id}")
    public Result<Void> deleteReview(@PathVariable("id") Long reviewId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return houseReviewService.deleteReview(reviewId, userId);
    }

    /**
     * 获取评价详情
     */
    @GetMapping("/detail/{id}")
    public Result<HouseReview> getReviewDetail(@PathVariable("id") Long reviewId) {
        return houseReviewService.getReviewById(reviewId);
    }

    /**
     * 获取房源的评价列表
     */
    @GetMapping("/house/{houseId}")
    public Result<List<HouseReview>> getHouseReviews(@PathVariable("houseId") Long houseId) {
        return houseReviewService.getHouseReviews(houseId);
    }

    /**
     * 获取用户的评价列表
     */
    @GetMapping("/user")
    public Result<List<HouseReview>> getUserReviews(HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return houseReviewService.getUserReviews(userId);
    }

    /**
     * 获取房源评价统计数据
     */
    @GetMapping("/statistics/{houseId}")
    public Result<Map<String, Object>> getHouseReviewStatistics(@PathVariable("houseId") Long houseId) {
        return houseReviewService.getHouseReviewStatistics(houseId);
    }

    /**
     * 检查用户是否已评价房源
     */
    @GetMapping("/check/{houseId}")
    public Result<Boolean> checkUserReviewed(@PathVariable("houseId") Long houseId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return houseReviewService.checkUserReviewed(houseId, userId);
    }
}

backend\src\main\java\com\rental\controller\ReviewReplyController.java

package com.rental.controller;

import com.rental.dto.ReplyDTO;
import com.rental.entity.ReviewReply;
import com.rental.dto.Result;
import com.rental.service.ReviewReplyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;

/**
 * 评价回复控制器
 */
@RestController
@RequestMapping("/reply")
public class ReviewReplyController {

    @Autowired
    private ReviewReplyService reviewReplyService;

    /**
     * 提交评价回复
     */
    @PostMapping("/submit")
    public Result<ReviewReply> submitReply(@RequestBody @Valid ReplyDTO replyDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return reviewReplyService.submitReply(replyDTO, userId);
    }

    /**
     * 更新评价回复
     */
    @PutMapping("/update/{id}")
    public Result<Void> updateReply(@PathVariable("id") Long replyId, @RequestBody @Valid ReplyDTO replyDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return reviewReplyService.updateReply(replyId, replyDTO, userId);
    }

    /**
     * 删除评价回复
     */
    @DeleteMapping("/delete/{id}")
    public Result<Void> deleteReply(@PathVariable("id") Long replyId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return reviewReplyService.deleteReply(replyId, userId);
    }

    /**
     * 获取回复详情
     */
    @GetMapping("/detail/{id}")
    public Result<ReviewReply> getReplyDetail(@PathVariable("id") Long replyId) {
        return reviewReplyService.getReplyById(replyId);
    }

    /**
     * 获取评价的回复列表
     */
    @GetMapping("/review/{reviewId}")
    public Result<List<ReviewReply>> getReviewReplies(@PathVariable("reviewId") Long reviewId) {
        return reviewReplyService.getReviewReplies(reviewId);
    }
}
3.1 API Services

backend\src\main\java\com\rental\controller\UserController.java

package com.rental.controller;

import com.rental.dto.LoginDTO;
import com.rental.dto.RegisterDTO;
import com.rental.dto.Result;
import com.rental.dto.UserDTO;
import com.rental.entity.User;
import com.rental.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 用户控制器
 */
@RestController
@RequestMapping("/api/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 用户登录
     */
    @PostMapping("/login")
    public Result<UserDTO> login(@RequestBody @Valid LoginDTO loginDTO) {
        UserDTO userDTO = userService.login(loginDTO);
        return Result.success(userDTO);
    }

    /**
     * 用户注册
     */
    @PostMapping("/register")
    public Result<UserDTO> register(@RequestBody @Valid RegisterDTO registerDTO) {
        UserDTO userDTO = userService.register(registerDTO);
        return Result.success(userDTO);
    }

    /**
     * 获取用户信息
     */
    @GetMapping("/{id}")
    public Result<UserDTO> getUserInfo(@PathVariable Long id) {
        UserDTO userDTO = userService.getUserById(id);
        if (userDTO == null) {
            return Result.error("用户不存在");
        }
        return Result.success(userDTO);
    }

    /**
     * 更新用户信息
     */
    @PutMapping
    public Result<Boolean> updateUser(@RequestBody User user) {
        boolean result = userService.updateUser(user);
        return Result.success(result);
    }

    /**
     * 更新用户状态
     */
    @PutMapping("/{id}/status/{status}")
    public Result<Boolean> updateUserStatus(@PathVariable Long id, @PathVariable Integer status) {
        boolean result = userService.updateUserStatus(id, status);
        return Result.success(result);
    }

    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public Result<Boolean> deleteUser(@PathVariable Long id) {
        boolean result = userService.deleteUser(id);
        return Result.success(result);
    }

    /**
     * 修改密码
     */
    @PutMapping("/password")
    public Result<Boolean> updatePassword(@RequestParam Long id, 
                                         @RequestParam String oldPassword, 
                                         @RequestParam String newPassword) {
        boolean result = userService.updatePassword(id, oldPassword, newPassword);
        return Result.success(result);
    }

    /**
     * 获取用户列表
     */
    @GetMapping("/list")
    public Result<List<UserDTO>> getUserList(User user) {
        List<UserDTO> userList = userService.getUserList(user);
        return Result.success(userList);
    }
}

backend\src\main\java\com\rental\controller\VerificationController.java

package com.rental.controller;

import com.rental.dto.LandlordVerificationDTO;
import com.rental.dto.Result;
import com.rental.dto.StudentVerificationDTO;
import com.rental.entity.LandlordVerification;
import com.rental.entity.StudentVerification;
import com.rental.service.VerificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 认证控制器
 */
@RestController
@RequestMapping("/api/verification")
public class VerificationController {

    @Autowired
    private VerificationService verificationService;

    /**
     * 提交学生认证
     */
    @PostMapping("/student")
    public Result<Boolean> submitStudentVerification(@RequestBody @Valid StudentVerificationDTO verificationDTO) {
        boolean result = verificationService.submitStudentVerification(verificationDTO);
        return Result.success(result);
    }

    /**
     * 提交房东认证
     */
    @PostMapping("/landlord")
    public Result<Boolean> submitLandlordVerification(@RequestBody @Valid LandlordVerificationDTO verificationDTO) {
        boolean result = verificationService.submitLandlordVerification(verificationDTO);
        return Result.success(result);
    }

    /**
     * 获取用户的学生认证信息
     */
    @GetMapping("/student/user/{userId}")
    public Result<StudentVerification> getStudentVerification(@PathVariable Long userId) {
        StudentVerification verification = verificationService.getStudentVerificationByUserId(userId);
        return Result.success(verification);
    }

    /**
     * 获取用户的房东认证信息
     */
    @GetMapping("/landlord/user/{userId}")
    public Result<LandlordVerification> getLandlordVerification(@PathVariable Long userId) {
        LandlordVerification verification = verificationService.getLandlordVerificationByUserId(userId);
        return Result.success(verification);
    }

    /**
     * 获取学生认证列表
     */
    @GetMapping("/student/list")
    public Result<List<StudentVerification>> getStudentVerificationList(StudentVerification verification) {
        List<StudentVerification> verificationList = verificationService.getStudentVerificationList(verification);
        return Result.success(verificationList);
    }

    /**
     * 获取房东认证列表
     */
    @GetMapping("/landlord/list")
    public Result<List<LandlordVerification>> getLandlordVerificationList(LandlordVerification verification) {
        List<LandlordVerification> verificationList = verificationService.getLandlordVerificationList(verification);
        return Result.success(verificationList);
    }

    /**
     * 审核学生认证
     */
    @PutMapping("/student/{id}/audit")
    public Result<Boolean> auditStudentVerification(@PathVariable Long id, 
                                                  @RequestParam Integer status, 
                                                  @RequestParam(required = false) String remark) {
        boolean result = verificationService.auditStudentVerification(id, status, remark);
        return Result.success(result);
    }

    /**
     * 审核房东认证
     */
    @PutMapping("/landlord/{id}/audit")
    public Result<Boolean> auditLandlordVerification(@PathVariable Long id, 
                                                   @RequestParam Integer status, 
                                                   @RequestParam(required = false) String remark) {
        boolean result = verificationService.auditLandlordVerification(id, status, remark);
        return Result.success(result);
    }
}

backend\src\main\java\com\rental\controller\ViewingFeedbackController.java

package com.rental.controller;

import com.rental.dto.FeedbackDTO;
import com.rental.entity.ViewingFeedback;
import com.rental.dto.Result;
import com.rental.service.ViewingFeedbackService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;

/**
 * 看房反馈控制器
 */
@RestController
@RequestMapping("/feedback")
public class ViewingFeedbackController {

    @Autowired
    private ViewingFeedbackService viewingFeedbackService;

    /**
     * 提交看房反馈
     */
    @PostMapping("/submit")
    public Result<ViewingFeedback> submitFeedback(@RequestBody @Valid FeedbackDTO feedbackDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return viewingFeedbackService.submitFeedback(feedbackDTO, userId);
    }

    /**
     * 更新看房反馈
     */
    @PutMapping("/update/{id}")
    public Result<Void> updateFeedback(@PathVariable("id") Long feedbackId, @RequestBody @Valid FeedbackDTO feedbackDTO, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return viewingFeedbackService.updateFeedback(feedbackId, feedbackDTO, userId);
    }

    /**
     * 删除看房反馈
     */
    @DeleteMapping("/delete/{id}")
    public Result<Void> deleteFeedback(@PathVariable("id") Long feedbackId, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return viewingFeedbackService.deleteFeedback(feedbackId, userId);
    }

    /**
     * 设置反馈是否公开
     */
    @PutMapping("/public/{id}")
    public Result<Void> setFeedbackPublic(@PathVariable("id") Long feedbackId, @RequestParam("isPublic") Integer isPublic, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return viewingFeedbackService.setFeedbackPublic(feedbackId, isPublic, userId);
    }

    /**
     * 获取反馈详情
     */
    @GetMapping("/detail/{id}")
    public Result<ViewingFeedback> getFeedbackDetail(@PathVariable("id") Long feedbackId) {
        return viewingFeedbackService.getFeedbackById(feedbackId);
    }

    /**
     * 获取用户的反馈列表
     */
    @GetMapping("/user")
    public Result<List<ViewingFeedback>> getUserFeedbacks(HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("userId");
        return viewingFeedbackService.getUserFeedbacks(userId);
    }

    /**
     * 获取房源的公开反馈列表
     */
    @GetMapping("/house/{houseId}")
    public Result<List<ViewingFeedback>> getHousePublicFeedbacks(@PathVariable("houseId") Long houseId) {
        return viewingFeedbackService.getHousePublicFeedbacks(houseId);
    }

    /**
     * 获取预约的反馈
     */
    @GetMapping("/appointment/{appointmentId}")
    public Result<ViewingFeedback> getAppointmentFeedback(@PathVariable("appointmentId") Long appointmentId) {
        return viewingFeedbackService.getAppointmentFeedback(appointmentId);
    }
}

backend\src\main\java\com\rental\dao\AppointmentDao.java

package com.rental.dao;

import com.rental.entity.Appointment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.Date;
import java.util.List;

/**
 * 预约DAO接口
 */
@Mapper
public interface AppointmentDao {
    
    /**
     * 根据ID查询预约
     */
    Appointment selectById(Long id);
    
    /**
     * 根据用户ID查询预约列表
     */
    List<Appointment> selectByUserId(Long userId);
    
    /**
     * 根据房东ID查询预约列表
     */
    List<Appointment> selectByLandlordId(Long landlordId);
    
    /**
     * 根据房源ID查询预约列表
     */
    List<Appointment> selectByHouseId(Long houseId);
    
    /**
     * 查询指定日期范围内的预约
     */
    List<Appointment> selectByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
    
    /**
     * 查询预约列表
     */
    List<Appointment> selectList(Appointment appointment);
    
    /**
     * 新增预约
     */
    int insert(Appointment appointment);
    
    /**
     * 更新预约
     */
    int update(Appointment appointment);
    
    /**
     * 更新预约状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status);
    
    /**
     * 删除预约
     */
    int deleteById(Long id);
    
    /**
     * 检查时间冲突
     */
    int checkTimeConflict(@Param("houseId") Long houseId, @Param("appointmentTime") Date appointmentTime);
}

backend\src\main\java\com\rental\dao\ComparisonDao.java

package com.rental.dao;

import com.rental.entity.Comparison;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 比较DAO接口
 */
@Repository
public interface ComparisonDao {
    
    /**
     * 根据ID查询比较
     * 
     * @param id ID
     * @return 比较对象
     */
    Comparison selectById(Long id);
    
    /**
     * 根据用户ID查询比较列表
     * 
     * @param userId 用户ID
     * @return 比较列表
     */
    List<Comparison> selectByUserId(Long userId);
    
    /**
     * 新增比较
     * 
     * @param comparison 比较对象
     * @return 影响行数
     */
    int insert(Comparison comparison);
    
    /**
     * 更新比较
     * 
     * @param comparison 比较对象
     * @return 影响行数
     */
    int update(Comparison comparison);
    
    /**
     * 删除比较
     * 
     * @param id ID
     * @return 影响行数
     */
    int deleteById(Long id);
    
    /**
     * 根据用户ID删除比较
     * 
     * @param userId 用户ID
     * @return 影响行数
     */
    int deleteByUserId(Long userId);
}

backend\src\main\java\com\rental\dao\FavoriteDao.java

package com.rental.dao;

import com.rental.entity.Favorite;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 收藏DAO接口
 */
@Mapper
public interface FavoriteDao {
    
    /**
     * 根据ID查询收藏
     */
    Favorite selectById(Long id);
    
    /**
     * 根据用户ID查询收藏列表
     */
    List<Favorite> selectByUserId(Long userId);
    
    /**
     * 根据用户ID和房源ID查询收藏
     */
    Favorite selectByUserIdAndHouseId(@Param("userId") Long userId, @Param("houseId") Long houseId);
    
    /**
     * 新增收藏
     */
    int insert(Favorite favorite);
    
    /**
     * 删除收藏
     */
    int deleteById(Long id);
    
    /**
     * 根据用户ID和房源ID删除收藏
     */
    int deleteByUserIdAndHouseId(@Param("userId") Long userId, @Param("houseId") Long houseId);
}
Frontend Files

backend\src\main\java\com\rental\dao\HouseDao.java

package com.rental.dao;

import com.rental.entity.House;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

/**
 * 房源DAO接口
 */
@Mapper
public interface HouseDao {
    
    /**
     * 根据ID查询房源
     */
    House selectById(Long id);
    
    /**
     * 根据房东ID查询房源列表
     */
    List<House> selectByLandlordId(Long landlordId);
    
    /**
     * 查询房源列表
     */
    List<House> selectList(House house);
    
    /**
     * 搜索房源
     */
    List<House> search(Map<String, Object> params);
    
    /**
     * 新增房源
     */
    int insert(House house);
    
    /**
     * 更新房源
     */
    int update(House house);
    
    /**
     * 更新房源状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status);
    
    /**
     * 删除房源
     */
    int deleteById(Long id);
    
    /**
     * 批量删除房源
     */
    int deleteBatchByIds(Long[] ids);
}

backend\src\main\java\com\rental\dao\HouseDetailDao.java

package com.rental.dao;

import com.rental.entity.HouseDetail;
import org.apache.ibatis.annotations.Mapper;

/**
 * 房源详情DAO接口
 */
@Mapper
public interface HouseDetailDao {
    
    /**
     * 根据ID查询房源详情
     */
    HouseDetail selectById(Long id);
    
    /**
     * 根据房源ID查询房源详情
     */
    HouseDetail selectByHouseId(Long houseId);
    
    /**
     * 新增房源详情
     */
    int insert(HouseDetail houseDetail);
    
    /**
     * 更新房源详情
     */
    int update(HouseDetail houseDetail);
    
    /**
     * 删除房源详情
     */
    int deleteById(Long id);
    
    /**
     * 根据房源ID删除房源详情
     */
    int deleteByHouseId(Long houseId);
}

backend\src\main\java\com\rental\dao\HouseImageDao.java

package com.rental.dao;

import com.rental.entity.HouseImage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 房源图片DAO接口
 */
@Mapper
public interface HouseImageDao {
    
    /**
     * 根据ID查询房源图片
     */
    HouseImage selectById(Long id);
    
    /**
     * 根据房源ID查询房源图片列表
     */
    List<HouseImage> selectByHouseId(Long houseId);
    
    /**
     * 根据房源ID查询封面图片
     */
    HouseImage selectCoverByHouseId(Long houseId);
    
    /**
     * 新增房源图片
     */
    int insert(HouseImage houseImage);
    
    /**
     * 批量新增房源图片
     */
    int insertBatch(List<HouseImage> houseImages);
    
    /**
     * 更新房源图片
     */
    int update(HouseImage houseImage);
    
    /**
     * 设置房源封面图片
     */
    int setCover(@Param("houseId") Long houseId, @Param("imageId") Long imageId);
    
    /**
     * 删除房源图片
     */
    int deleteById(Long id);
    
    /**
     * 根据房源ID删除房源图片
     */
    int deleteByHouseId(Long houseId);
}

backend\src\main\java\com\rental\dao\HouseReviewDao.java

package com.rental.dao;

import com.rental.entity.HouseReview;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 房源评价DAO接口
 */
@Mapper
public interface HouseReviewDao {
    
    /**
     * 根据ID查询房源评价
     */
    HouseReview selectById(Long id);
    
    /**
     * 根据房源ID查询房源评价列表
     */
    List<HouseReview> selectByHouseId(Long houseId);
    
    /**
     * 根据用户ID查询房源评价列表
     */
    List<HouseReview> selectByUserId(Long userId);
    
    /**
     * 根据房源ID和用户ID查询房源评价
     */
    HouseReview selectByHouseIdAndUserId(@Param("houseId") Long houseId, @Param("userId") Long userId);
    
    /**
     * 查询房源评价列表
     */
    List<HouseReview> selectList(HouseReview review);
    
    /**
     * 新增房源评价
     */
    int insert(HouseReview review);
    
    /**
     * 更新房源评价
     */
    int update(HouseReview review);
    
    /**
     * 删除房源评价
     */
    int deleteById(Long id);
    
    /**
     * 计算房源平均评分
     */
    Double calculateAverageRating(Long houseId);
}

backend\src\main\java\com\rental\dao\LandlordVerificationDao.java

package com.rental.dao;

import com.rental.entity.LandlordVerification;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 房东认证DAO接口
 */
@Mapper
public interface LandlordVerificationDao {
    
    /**
     * 根据ID查询房东认证
     */
    LandlordVerification selectById(Long id);
    
    /**
     * 根据用户ID查询房东认证
     */
    LandlordVerification selectByUserId(Long userId);
    
    /**
     * 查询房东认证列表
     */
    List<LandlordVerification> selectList(LandlordVerification verification);
    
    /**
     * 新增房东认证
     */
    int insert(LandlordVerification verification);
    
    /**
     * 更新房东认证
     */
    int update(LandlordVerification verification);
    
    /**
     * 更新房东认证状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status, @Param("remark") String remark);
    
    /**
     * 删除房东认证
     */
    int deleteById(Long id);
}

backend\src\main\java\com\rental\dao\PermissionDao.java

package com.rental.dao;

import com.rental.entity.Permission;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 权限DAO接口
 */
@Repository
public interface PermissionDao {
    
    /**
     * 根据ID查询权限
     * 
     * @param id 权限ID
     * @return 权限对象
     */
    Permission selectById(Long id);
    
    /**
     * 根据编码查询权限
     * 
     * @param code 权限编码
     * @return 权限对象
     */
    Permission selectByCode(String code);
    
    /**
     * 查询权限列表
     * 
     * @param permission 查询条件
     * @return 权限列表
     */
    List<Permission> selectList(Permission permission);
    
    /**
     * 根据角色ID查询权限列表
     * 
     * @param roleId 角色ID
     * @return 权限列表
     */
    List<Permission> selectByRoleId(Long roleId);
    
    /**
     * 根据用户ID查询权限列表
     * 
     * @param userId 用户ID
     * @return 权限列表
     */
    List<Permission> selectByUserId(Long userId);
    
    /**
     * 新增权限
     * 
     * @param permission 权限对象
     * @return 影响行数
     */
    int insert(Permission permission);
    
    /**
     * 更新权限
     * 
     * @param permission 权限对象
     * @return 影响行数
     */
    int update(Permission permission);
    
    /**
     * 删除权限
     * 
     * @param id 权限ID
     * @return 影响行数
     */
    int deleteById(Long id);
}

backend\src\main\java\com\rental\dao\ReviewReplyDao.java

package com.rental.dao;

import com.rental.entity.ReviewReply;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * 评价回复DAO接口
 */
@Mapper
public interface ReviewReplyDao {
    
    /**
     * 根据ID查询评价回复
     */
    ReviewReply selectById(Long id);
    
    /**
     * 根据评价ID查询评价回复列表
     */
    List<ReviewReply> selectByReviewId(Long reviewId);
    
    /**
     * 根据用户ID查询评价回复列表
     */
    List<ReviewReply> selectByUserId(Long userId);
    
    /**
     * 新增评价回复
     */
    int insert(ReviewReply reply);
    
    /**
     * 更新评价回复
     */
    int update(ReviewReply reply);
    
    /**
     * 删除评价回复
     */
    int deleteById(Long id);
}
2.4 MyBatis Mapper XML Files

backend\src\main\java\com\rental\dao\RoleDao.java

package com.rental.dao;

import com.rental.entity.Role;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 角色DAO接口
 */
@Repository
public interface RoleDao {
    
    /**
     * 根据ID查询角色
     * 
     * @param id 角色ID
     * @return 角色对象
     */
    Role selectById(Long id);
    
    /**
     * 根据编码查询角色
     * 
     * @param code 角色编码
     * @return 角色对象
     */
    Role selectByCode(String code);
    
    /**
     * 查询角色列表
     * 
     * @param role 查询条件
     * @return 角色列表
     */
    List<Role> selectList(Role role);
    
    /**
     * 根据用户ID查询角色列表
     * 
     * @param userId 用户ID
     * @return 角色列表
     */
    List<Role> selectByUserId(Long userId);
    
    /**
     * 新增角色
     * 
     * @param role 角色对象
     * @return 影响行数
     */
    int insert(Role role);
    
    /**
     * 更新角色
     * 
     * @param role 角色对象
     * @return 影响行数
     */
    int update(Role role);
    
    /**
     * 删除角色
     * 
     * @param id 角色ID
     * @return 影响行数
     */
    int deleteById(Long id);
}

backend\src\main\java\com\rental\dao\StudentVerificationDao.java

package com.rental.dao;

import com.rental.entity.StudentVerification;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 学生认证DAO接口
 */
@Mapper
public interface StudentVerificationDao {
    
    /**
     * 根据ID查询学生认证
     */
    StudentVerification selectById(Long id);
    
    /**
     * 根据用户ID查询学生认证
     */
    StudentVerification selectByUserId(Long userId);
    
    /**
     * 查询学生认证列表
     */
    List<StudentVerification> selectList(StudentVerification verification);
    
    /**
     * 新增学生认证
     */
    int insert(StudentVerification verification);
    
    /**
     * 更新学生认证
     */
    int update(StudentVerification verification);
    
    /**
     * 更新学生认证状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status, @Param("remark") String remark);
    
    /**
     * 删除学生认证
     */
    int deleteById(Long id);
}

backend\src\main\java\com\rental\dao\UserDao.java

package com.rental.dao;

import com.rental.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 用户DAO接口
 */
@Mapper
public interface UserDao {
    
    /**
     * 根据ID查询用户
     */
    User selectById(Long id);
    
    /**
     * 根据用户名查询用户
     */
    User selectByUsername(String username);
    
    /**
     * 根据手机号查询用户
     */
    User selectByPhone(String phone);
    
    /**
     * 查询用户列表
     */
    List<User> selectList(User user);
    
    /**
     * 新增用户
     */
    int insert(User user);
    
    /**
     * 更新用户
     */
    int update(User user);
    
    /**
     * 更新用户状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status);
    
    /**
     * 删除用户
     */
    int deleteById(Long id);
    
    /**
     * 新增用户角色关联
     */
    int insertUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId);
    
    /**
     * 删除用户角色关联
     */
    int deleteUserRole(Long userId);
}

backend\src\main\java\com\rental\dao\ViewingFeedbackDao.java

package com.rental.dao;

import com.rental.entity.ViewingFeedback;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 看房反馈DAO接口
 */
@Mapper
public interface ViewingFeedbackDao {
    
    /**
     * 根据ID查询看房反馈
     */
    ViewingFeedback selectById(Long id);
    
    /**
     * 根据预约ID查询看房反馈
     */
    ViewingFeedback selectByAppointmentId(Long appointmentId);
    
    /**
     * 根据用户ID查询看房反馈列表
     */
    List<ViewingFeedback> selectByUserId(Long userId);
    
    /**
     * 根据房源ID查询公开的看房反馈列表
     */
    List<ViewingFeedback> selectPublicByHouseId(Long houseId);
    
    /**
     * 查询看房反馈列表
     */
    List<ViewingFeedback> selectList(ViewingFeedback feedback);
    
    /**
     * 新增看房反馈
     */
    int insert(ViewingFeedback feedback);
    
    /**
     * 更新看房反馈
     */
    int update(ViewingFeedback feedback);
    
    /**
     * 更新是否公开
     */
    int updateIsPublic(@Param("id") Long id, @Param("isPublic") Integer isPublic);
    
    /**
     * 删除看房反馈
     */
    int deleteById(Long id);
}

backend\src\main\java\com\rental\dto\AppointmentDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.Future;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Date;

/**
 * 预约DTO
 */
@Data
public class AppointmentDTO {

    /**
     * 房源ID
     */
    @NotNull(message = "房源ID不能为空")
    private Long houseId;

    /**
     * 预约时间
     */
    @NotNull(message = "预约时间不能为空")
    @Future(message = "预约时间必须是将来的时间")
    private Date appointmentTime;

    /**
     * 联系人姓名
     */
    @NotBlank(message = "联系人姓名不能为空")
    private String contactName;

    /**
     * 联系电话
     */
    @NotBlank(message = "联系电话不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号码格式不正确")
    private String contactPhone;

    /**
     * 预约备注
     */
    private String appointmentNotes;
}

backend\src\main\java\com\rental\dto\FeedbackDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.*;

/**
 * 看房反馈DTO
 */
@Data
public class FeedbackDTO {

    /**
     * 预约ID
     */
    @NotNull(message = "预约ID不能为空")
    private Long appointmentId;

    /**
     * 反馈内容
     */
    @NotBlank(message = "反馈内容不能为空")
    @Size(min = 10, max = 500, message = "反馈内容长度必须在10-500个字符之间")
    private String feedbackContent;

    /**
     * 满意度:1-5星
     */
    @NotNull(message = "满意度不能为空")
    @Min(value = 1, message = "满意度最小为1星")
    @Max(value = 5, message = "满意度最大为5星")
    private Integer satisfactionLevel;

    /**
     * 是否公开:0-私密,1-公开
     */
    @NotNull(message = "是否公开不能为空")
    private Integer isPublic;
}

backend\src\main\java\com\rental\dto\HouseDetailDTO.java

package com.rental.dto;

import lombok.Data;

import java.io.Serializable;

/**
 * 房源详情DTO
 */
@Data
public class HouseDetailDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 房屋类型:1-普通住宅,2-公寓,3-别墅,4-其他
     */
    private Integer houseCategory;

    /**
     * 出租方式:1-整租,2-合租
     */
    private Integer rentType;

    /**
     * 支付方式:1-月付,2-季付,3-半年付,4-年付
     */
    private Integer paymentType;

    /**
     * 是否有电梯:0-无,1-有
     */
    private Integer hasElevator;

    /**
     * 供暖方式:1-集中供暖,2-自采暖,3-无供暖
     */
    private Integer heatingType;

    /**
     * 水费
     */
    private Double waterFee;

    /**
     * 电费
     */
    private Double electricityFee;

    /**
     * 燃气费
     */
    private Double gasFee;

    /**
     * 网费
     */
    private Double internetFee;

    /**
     * 物业费
     */
    private Double propertyFee;

    /**
     * 车位:0-无,1-有
     */
    private Integer hasParking;

    /**
     * 入住时间
     */
    private String checkInTime;

    /**
     * 最短租期
     */
    private String minRentPeriod;

    /**
     * 最长租期
     */
    private String maxRentPeriod;

    /**
     * 配套设施,逗号分隔:1-床,2-衣柜,3-沙发,4-电视,5-冰箱,6-洗衣机,7-空调,8-热水器,9-宽带,10-暖气,11-燃气灶,12-独立卫生间,13-阳台
     */
    private String facilities;

    /**
     * 交通状况
     */
    private String transportation;

    /**
     * 周边配套
     */
    private String surroundings;

    /**
     * 详细描述
     */
    private String description;
}

backend\src\main\java\com\rental\dto\HouseDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * 房源DTO
 */
@Data
public class HouseDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 房源ID
     */
    private Long id;

    /**
     * 房东ID
     */
    @NotNull(message = "房东ID不能为空")
    private Long landlordId;

    /**
     * 标题
     */
    @NotBlank(message = "标题不能为空")
    private String title;

    /**
     * 价格
     */
    @NotNull(message = "价格不能为空")
    private Double price;

    /**
     * 面积
     */
    @NotNull(message = "面积不能为空")
    private Double area;

    /**
     * 户型
     */
    @NotBlank(message = "户型不能为空")
    private String houseType;

    /**
     * 楼层
     */
    private String floor;

    /**
     * 朝向
     */
    private String orientation;

    /**
     * 装修
     */
    private String decoration;

    /**
     * 小区
     */
    @NotBlank(message = "小区不能为空")
    private String community;

    /**
     * 地址
     */
    @NotBlank(message = "地址不能为空")
    private String address;

    /**
     * 经度
     */
    private Double longitude;

    /**
     * 纬度
     */
    private Double latitude;

    /**
     * 联系人
     */
    @NotBlank(message = "联系人不能为空")
    private String contact;

    /**
     * 联系电话
     */
    @NotBlank(message = "联系电话不能为空")
    private String contactPhone;

    /**
     * 状态:0-下架,1-上架
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 房源详情
     */
    private HouseDetailDTO detail;

    /**
     * 房源图片列表
     */
    private List<String> images;
}

backend\src\main\java\com\rental\dto\HouseSearchDTO.java

package com.rental.dto;

import lombok.Data;

import java.io.Serializable;

/**
 * 房源搜索DTO
 */
@Data
public class HouseSearchDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 关键词
     */
    private String keyword;

    /**
     * 最低价格
     */
    private Double minPrice;

    /**
     * 最高价格
     */
    private Double maxPrice;

    /**
     * 户型
     */
    private String houseType;

    /**
     * 最小面积
     */
    private Double minArea;

    /**
     * 最大面积
     */
    private Double maxArea;

    /**
     * 朝向
     */
    private String orientation;

    /**
     * 装修
     */
    private String decoration;

    /**
     * 房屋类型:1-普通住宅,2-公寓,3-别墅,4-其他
     */
    private Integer houseCategory;

    /**
     * 出租方式:1-整租,2-合租
     */
    private Integer rentType;

    /**
     * 是否有电梯:0-无,1-有
     */
    private Integer hasElevator;

    /**
     * 供暖方式:1-集中供暖,2-自采暖,3-无供暖
     */
    private Integer heatingType;

    /**
     * 配套设施,逗号分隔:1-床,2-衣柜,3-沙发,4-电视,5-冰箱,6-洗衣机,7-空调,8-热水器,9-宽带,10-暖气,11-燃气灶,12-独立卫生间,13-阳台
     */
    private String facilities;

    /**
     * 当前页码
     */
    private Integer pageNum = 1;

    /**
     * 每页数量
     */
    private Integer pageSize = 10;
}

backend\src\main\java\com\rental\dto\LandlordVerificationDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
 * 房东认证DTO
 */
@Data
public class LandlordVerificationDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    @NotNull(message = "用户ID不能为空")
    private Long userId;

    /**
     * 真实姓名
     */
    @NotBlank(message = "真实姓名不能为空")
    private String realName;

    /**
     * 身份证号
     */
    @NotBlank(message = "身份证号不能为空")
    private String idCard;

    /**
     * 身份证正面照片
     */
    @NotBlank(message = "身份证正面照片不能为空")
    private String idCardFrontImg;

    /**
     * 身份证背面照片
     */
    @NotBlank(message = "身份证背面照片不能为空")
    private String idCardBackImg;

    /**
     * 手持身份证照片
     */
    @NotBlank(message = "手持身份证照片不能为空")
    private String idCardHandImg;
}

backend\src\main\java\com\rental\dto\LoginDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import java.io.Serializable;

/**
 * 登录请求DTO
 */
@Data
public class LoginDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户名/手机号
     */
    @NotBlank(message = "用户名不能为空")
    private String username;

    /**
     * 密码
     */
    @NotBlank(message = "密码不能为空")
    private String password;
}

backend\src\main\java\com\rental\dto\PageResult.java

package com.rental.dto;

import lombok.Data;

import java.io.Serializable;
import java.util.List;

/**
 * 分页结果
 */
@Data
public class PageResult<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 总记录数
     */
    private Long total;

    /**
     * 当前页码
     */
    private Integer pageNum;

    /**
     * 每页数量
     */
    private Integer pageSize;

    /**
     * 总页数
     */
    private Integer pages;

    /**
     * 数据列表
     */
    private List<T> list;

    /**
     * 构造方法
     */
    public PageResult() {
    }

    /**
     * 构造方法
     */
    public PageResult(Long total, List<T> list) {
        this.total = total;
        this.list = list;
    }

    /**
     * 构造方法
     */
    public PageResult(Long total, Integer pageNum, Integer pageSize, List<T> list) {
        this.total = total;
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.list = list;
        this.pages = (int) Math.ceil((double) total / pageSize);
    }
}

backend\src\main\java\com\rental\dto\RegisterDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.io.Serializable;

/**
 * 注册请求DTO
 */
@Data
public class RegisterDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    @Pattern(regexp = "^[a-zA-Z0-9_]{4,16}$", message = "用户名必须为4-16位字母、数字或下划线")
    private String username;

    /**
     * 密码
     */
    @NotBlank(message = "密码不能为空")
    @Pattern(regexp = "^[a-zA-Z0-9_]{6,20}$", message = "密码必须为6-20位字母、数字或下划线")
    private String password;

    /**
     * 手机号
     */
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;

    /**
     * 角色:STUDENT-学生,LANDLORD-房东
     */
    @NotBlank(message = "角色不能为空")
    private String role;
}

backend\src\main\java\com\rental\dto\ReplyDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

/**
 * 评价回复DTO
 */
@Data
public class ReplyDTO {

    /**
     * 评价ID
     */
    @NotNull(message = "评价ID不能为空")
    private Long reviewId;

    /**
     * 回复内容
     */
    @NotBlank(message = "回复内容不能为空")
    @Size(min = 5, max = 200, message = "回复内容长度必须在5-200个字符之间")
    private String content;
}
2.3 DAO Interfaces

backend\src\main\java\com\rental\dto\Result.java

package com.rental.dto;

import lombok.Data;

import java.io.Serializable;

/**
 * 统一返回结果
 */
@Data
public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 状态码
     */
    private Integer code;

    /**
     * 消息
     */
    private String message;

    /**
     * 数据
     */
    private T data;

    /**
     * 成功
     */
    public static <T> Result<T> success() {
        return success(null);
    }

    /**
     * 成功
     */
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("操作成功");
        result.setData(data);
        return result;
    }

    /**
     * 失败
     */
    public static <T> Result<T> error() {
        return error(500, "操作失败");
    }

    /**
     * 失败
     */
    public static <T> Result<T> error(String message) {
        return error(500, message);
    }

    /**
     * 失败
     */
    public static <T> Result<T> error(Integer code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
}

backend\src\main\java\com\rental\dto\ReviewDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.*;
import java.util.List;

/**
 * 房源评价DTO
 */
@Data
public class ReviewDTO {

    /**
     * 房源ID
     */
    @NotNull(message = "房源ID不能为空")
    private Long houseId;

    /**
     * 评价内容
     */
    @NotBlank(message = "评价内容不能为空")
    @Size(min = 10, max = 500, message = "评价内容长度必须在10-500个字符之间")
    private String content;

    /**
     * 总体评分:1-5星
     */
    @NotNull(message = "总体评分不能为空")
    @Min(value = 1, message = "评分最小为1星")
    @Max(value = 5, message = "评分最大为5星")
    private Integer rating;

    /**
     * 位置评分:1-5星
     */
    @NotNull(message = "位置评分不能为空")
    @Min(value = 1, message = "评分最小为1星")
    @Max(value = 5, message = "评分最大为5星")
    private Integer locationRating;

    /**
     * 清洁度评分:1-5星
     */
    @NotNull(message = "清洁度评分不能为空")
    @Min(value = 1, message = "评分最小为1星")
    @Max(value = 5, message = "评分最大为5星")
    private Integer cleanlinessRating;

    /**
     * 性价比评分:1-5星
     */
    @NotNull(message = "性价比评分不能为空")
    @Min(value = 1, message = "评分最小为1星")
    @Max(value = 5, message = "评分最大为5星")
    private Integer valueRating;

    /**
     * 房东评分:1-5星
     */
    @NotNull(message = "房东评分不能为空")
    @Min(value = 1, message = "评分最小为1星")
    @Max(value = 5, message = "评分最大为5星")
    private Integer landlordRating;

    /**
     * 评价图片
     */
    private List<String> images;
}

backend\src\main\java\com\rental\dto\StudentVerificationDTO.java

package com.rental.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
 * 学生认证DTO
 */
@Data
public class StudentVerificationDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    @NotNull(message = "用户ID不能为空")
    private Long userId;

    /**
     * 学号
     */
    @NotBlank(message = "学号不能为空")
    private String studentId;

    /**
     * 学校
     */
    @NotBlank(message = "学校不能为空")
    private String school;

    /**
     * 学院
     */
    private String college;

    /**
     * 专业
     */
    private String major;

    /**
     * 入学年份
     */
    private Integer admissionYear;

    /**
     * 学生证照片
     */
    @NotBlank(message = "学生证照片不能为空")
    private String studentCardImg;
}

backend\src\main\java\com\rental\dto\UserDTO.java

package com.rental.dto;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * 用户DTO
 */
@Data
public class UserDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 真实姓名
     */
    private String realName;

    /**
     * 手机号
     */
    private String phone;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 头像
     */
    private String avatar;

    /**
     * 性别:0-女,1-男
     */
    private Integer gender;

    /**
     * 角色:STUDENT-学生,LANDLORD-房东,ADMIN-管理员
     */
    private String role;

    /**
     * 状态:0-禁用,1-正常
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 角色列表
     */
    private List<String> roles;

    /**
     * 权限列表
     */
    private List<String> permissions;

    /**
     * 认证状态:0-未认证,1-已认证,2-认证中,3-认证失败
     */
    private Integer verificationStatus;

    /**
     * token
     */
    private String token;
}

backend\src\main\java\com\rental\entity\Appointment.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 预约看房实体类
 */
@Data
public class Appointment implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 预约ID
     */
    private Long id;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 房东ID
     */
    private Long landlordId;

    /**
     * 预约时间
     */
    private Date appointmentTime;

    /**
     * 联系人姓名
     */
    private String contactName;

    /**
     * 联系电话
     */
    private String contactPhone;

    /**
     * 预约备注
     */
    private String appointmentNotes;

    /**
     * 状态:0-待确认,1-已确认,2-已取消,3-已完成
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\Comparison.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 比较实体类
 */
@Data
public class Comparison implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 房源ID列表,逗号分隔
     */
    private String houseIds;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\Favorite.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 收藏实体类
 */
@Data
public class Favorite implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 创建时间
     */
    private Date createTime;
}
DAO Interfaces

backend\src\main\java\com\rental\entity\House.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 房源实体类
 */
@Data
public class House implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 房源ID
     */
    private Long id;

    /**
     * 房东ID
     */
    private Long landlordId;

    /**
     * 标题
     */
    private String title;

    /**
     * 租金
     */
    private BigDecimal price;

    /**
     * 面积
     */
    private BigDecimal area;

    /**
     * 户型
     */
    private String houseType;

    /**
     * 楼层
     */
    private String floor;

    /**
     * 朝向
     */
    private String orientation;

    /**
     * 装修
     */
    private String decoration;

    /**
     * 小区名称
     */
    private String community;

    /**
     * 详细地址
     */
    private String address;

    /**
     * 经度
     */
    private BigDecimal longitude;

    /**
     * 纬度
     */
    private BigDecimal latitude;

    /**
     * 联系人
     */
    private String contact;

    /**
     * 联系电话
     */
    private String contactPhone;

    /**
     * 状态:0-待审核,1-已上架,2-已下架,3-已出租
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\HouseDetail.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房源详情实体类
 */
@Data
public class HouseDetail implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 房源类别:整租、合租
     */
    private String houseCategory;

    /**
     * 出租方式:月付、季付、半年付、年付
     */
    private String rentType;

    /**
     * 付款方式:押一付一、押一付三、押二付三等
     */
    private String paymentType;

    /**
     * 是否有电梯:0-无,1-有
     */
    private Integer hasElevator;

    /**
     * 供暖方式
     */
    private String heatingType;

    /**
     * 水费
     */
    private String waterFee;

    /**
     * 电费
     */
    private String electricityFee;

    /**
     * 燃气费
     */
    private String gasFee;

    /**
     * 网费
     */
    private String internetFee;

    /**
     * 物业费
     */
    private String propertyFee;

    /**
     * 是否有停车位:0-无,1-有
     */
    private Integer hasParking;

    /**
     * 入住时间
     */
    private Date checkInTime;

    /**
     * 最短租期(月)
     */
    private Integer minRentPeriod;

    /**
     * 最长租期(月)
     */
    private Integer maxRentPeriod;

    /**
     * 配套设施
     */
    private String facilities;

    /**
     * 交通情况
     */
    private String transportation;

    /**
     * 周边配套
     */
    private String surroundings;

    /**
     * 房源描述
     */
    private String description;
}

backend\src\main\java\com\rental\entity\HouseImage.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房源图片实体类
 */
@Data
public class HouseImage implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 图片URL
     */
    private String url;

    /**
     * 是否封面:0-否,1-是
     */
    private Integer isCover;

    /**
     * 排序
     */
    private Integer sort;

    /**
     * 创建时间
     */
    private Date createTime;
}

backend\src\main\java\com\rental\entity\HouseReview.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房源评价实体类
 */
@Data
public class HouseReview implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 评价ID
     */
    private Long id;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 评价内容
     */
    private String content;

    /**
     * 评分:1-5星
     */
    private Integer rating;

    /**
     * 位置评分:1-5星
     */
    private Integer locationRating;

    /**
     * 清洁度评分:1-5星
     */
    private Integer cleanlinessRating;

    /**
     * 性价比评分:1-5星
     */
    private Integer valueRating;

    /**
     * 房东评分:1-5星
     */
    private Integer landlordRating;

    /**
     * 评价图片,多个图片用逗号分隔
     */
    private String images;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\LandlordVerification.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房东认证实体类
 */
@Data
public class LandlordVerification implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 真实姓名
     */
    private String realName;

    /**
     * 身份证号
     */
    private String idCard;

    /**
     * 身份证正面照
     */
    private String idCardFront;

    /**
     * 身份证背面照
     */
    private String idCardBack;

    /**
     * 房产证照片
     */
    private String houseCertificate;

    /**
     * 状态:0-待审核,1-已通过,2-已拒绝
     */
    private Integer status;

    /**
     * 备注
     */
    private String remark;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\Permission.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 权限实体类
 */
@Data
public class Permission implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 权限ID
     */
    private Long id;

    /**
     * 权限名称
     */
    private String name;

    /**
     * 权限编码
     */
    private String code;

    /**
     * 权限描述
     */
    private String description;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\ReviewReply.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 评价回复实体类
 */
@Data
public class ReviewReply implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 回复ID
     */
    private Long id;

    /**
     * 评价ID
     */
    private Long reviewId;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 回复内容
     */
    private String content;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}
2.2 DTO Classes

backend\src\main\java\com\rental\entity\Role.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 角色实体类
 */
@Data
public class Role implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 角色ID
     */
    private Long id;

    /**
     * 角色名称
     */
    private String name;

    /**
     * 角色编码
     */
    private String code;

    /**
     * 角色描述
     */
    private String description;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\StudentVerification.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 学生认证实体类
 */
@Data
public class StudentVerification implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 学号
     */
    private String studentId;

    /**
     * 学校
     */
    private String school;

    /**
     * 学院
     */
    private String college;

    /**
     * 专业
     */
    private String major;

    /**
     * 身份证号
     */
    private String idCard;

    /**
     * 身份证正面照
     */
    private String idCardFront;

    /**
     * 身份证背面照
     */
    private String idCardBack;

    /**
     * 学生证照片
     */
    private String studentCard;

    /**
     * 状态:0-待审核,1-已通过,2-已拒绝
     */
    private Integer status;

    /**
     * 备注
     */
    private String remark;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}

backend\src\main\java\com\rental\entity\User.java

package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 用户实体类
 */
@Data
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 真实姓名
     */
    private String realName;

    /**
     * 手机号码
     */
    private String phone;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 头像
     */
    private String avatar;

    /**
     * 性别:0-未知,1-男,2-女
     */
    private Integer gender;

    /**
     * 状态:0-禁用,1-正常
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}
2. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\Role.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 角色实体类
 */
@Data
public class Role implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 角色ID
     */
    private Long id;

    /**
     * 角色名称
     */
    private String name;

    /**
     * 角色编码
     */
    private String code;

    /**
     * 角色描述
     */
    private String description;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}
3. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\House.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 房源实体类
 */
@Data
public class House implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 房源ID
     */
    private Long id;

    /**
     * 房东ID
     */
    private Long landlordId;

    /**
     * 标题
     */
    private String title;

    /**
     * 租金
     */
    private BigDecimal price;

    /**
     * 面积
     */
    private BigDecimal area;

    /**
     * 户型
     */
    private String houseType;

    /**
     * 楼层
     */
    private String floor;

    /**
     * 朝向
     */
    private String orientation;

    /**
     * 装修
     */
    private String decoration;

    /**
     * 小区名称
     */
    private String community;

    /**
     * 详细地址
     */
    private String address;

    /**
     * 经度
     */
    private BigDecimal longitude;

    /**
     * 纬度
     */
    private BigDecimal latitude;

    /**
     * 联系人
     */
    private String contact;

    /**
     * 联系电话
     */
    private String contactPhone;

    /**
     * 状态:0-待审核,1-已上架,2-已下架,3-已出租
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}
4. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\HouseDetail.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房源详情实体类
 */
@Data
public class HouseDetail implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 房源类别:整租、合租
     */
    private String houseCategory;

    /**
     * 出租方式:月付、季付、半年付、年付
     */
    private String rentType;

    /**
     * 付款方式:押一付一、押一付三、押二付三等
     */
    private String paymentType;

    /**
     * 是否有电梯:0-无,1-有
     */
    private Integer hasElevator;

    /**
     * 供暖方式
     */
    private String heatingType;

    /**
     * 水费
     */
    private String waterFee;

    /**
     * 电费
     */
    private String electricityFee;

    /**
     * 燃气费
     */
    private String gasFee;

    /**
     * 网费
     */
    private String internetFee;

    /**
     * 物业费
     */
    private String propertyFee;

    /**
     * 是否有停车位:0-无,1-有
     */
    private Integer hasParking;

    /**
     * 入住时间
     */
    private Date checkInTime;

    /**
     * 最短租期(月)
     */
    private Integer minRentPeriod;

    /**
     * 最长租期(月)
     */
    private Integer maxRentPeriod;

    /**
     * 配套设施
     */
    private String facilities;

    /**
     * 交通情况
     */
    private String transportation;

    /**
     * 周边配套
     */
    private String surroundings;

    /**
     * 房源描述
     */
    private String description;
}
5. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\HouseImage.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房源图片实体类
 */
@Data
public class HouseImage implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 图片URL
     */
    private String url;

    /**
     * 是否封面:0-否,1-是
     */
    private Integer isCover;

    /**
     * 排序
     */
    private Integer sort;

    /**
     * 创建时间
     */
    private Date createTime;
}
6. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\StudentVerification.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 学生认证实体类
 */
@Data
public class StudentVerification implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 学号
     */
    private String studentId;

    /**
     * 学校
     */
    private String school;

    /**
     * 学院
     */
    private String college;

    /**
     * 专业
     */
    private String major;

    /**
     * 身份证号
     */
    private String idCard;

    /**
     * 身份证正面照
     */
    private String idCardFront;

    /**
     * 身份证背面照
     */
    private String idCardBack;

    /**
     * 学生证照片
     */
    private String studentCard;

    /**
     * 状态:0-待审核,1-已通过,2-已拒绝
     */
    private Integer status;

    /**
     * 备注
     */
    private String remark;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}
7. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\LandlordVerification.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 房东认证实体类
 */
@Data
public class LandlordVerification implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 真实姓名
     */
    private String realName;

    /**
     * 身份证号
     */
    private String idCard;

    /**
     * 身份证正面照
     */
    private String idCardFront;

    /**
     * 身份证背面照
     */
    private String idCardBack;

    /**
     * 房产证照片
     */
    private String houseCertificate;

    /**
     * 状态:0-待审核,1-已通过,2-已拒绝
     */
    private Integer status;

    /**
     * 备注
     */
    private String remark;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;
}
8. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\entity\Favorite.java

java
CopyInsert
package com.rental.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 收藏实体类
 */
@Data
public class Favorite implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 房源ID
     */
    private Long houseId;

    /**
     * 创建时间
     */
    private Date createTime;
}
DAO Interfaces
9. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\UserDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 用户DAO接口
 */
@Mapper
public interface UserDao {
    
    /**
     * 根据ID查询用户
     */
    User selectById(Long id);
    
    /**
     * 根据用户名查询用户
     */
    User selectByUsername(String username);
    
    /**
     * 根据手机号查询用户
     */
    User selectByPhone(String phone);
    
    /**
     * 查询用户列表
     */
    List<User> selectList(User user);
    
    /**
     * 新增用户
     */
    int insert(User user);
    
    /**
     * 更新用户
     */
    int update(User user);
    
    /**
     * 更新用户状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status);
    
    /**
     * 删除用户
     */
    int deleteById(Long id);
    
    /**
     * 新增用户角色关联
     */
    int insertUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId);
    
    /**
     * 删除用户角色关联
     */
    int deleteUserRole(Long userId);
}
10. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\HouseDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.House;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

/**
 * 房源DAO接口
 */
@Mapper
public interface HouseDao {
    
    /**
     * 根据ID查询房源
     */
    House selectById(Long id);
    
    /**
     * 根据房东ID查询房源列表
     */
    List<House> selectByLandlordId(Long landlordId);
    
    /**
     * 查询房源列表
     */
    List<House> selectList(House house);
    
    /**
     * 搜索房源
     */
    List<House> search(Map<String, Object> params);
    
    /**
     * 新增房源
     */
    int insert(House house);
    
    /**
     * 更新房源
     */
    int update(House house);
    
    /**
     * 更新房源状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status);
    
    /**
     * 删除房源
     */
    int deleteById(Long id);
    
    /**
     * 批量删除房源
     */
    int deleteBatchByIds(Long[] ids);
}
11. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\HouseDetailDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.HouseDetail;
import org.apache.ibatis.annotations.Mapper;

/**
 * 房源详情DAO接口
 */
@Mapper
public interface HouseDetailDao {
    
    /**
     * 根据ID查询房源详情
     */
    HouseDetail selectById(Long id);
    
    /**
     * 根据房源ID查询房源详情
     */
    HouseDetail selectByHouseId(Long houseId);
    
    /**
     * 新增房源详情
     */
    int insert(HouseDetail houseDetail);
    
    /**
     * 更新房源详情
     */
    int update(HouseDetail houseDetail);
    
    /**
     * 删除房源详情
     */
    int deleteById(Long id);
    
    /**
     * 根据房源ID删除房源详情
     */
    int deleteByHouseId(Long houseId);
}
12. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\HouseImageDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.HouseImage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 房源图片DAO接口
 */
@Mapper
public interface HouseImageDao {
    
    /**
     * 根据ID查询房源图片
     */
    HouseImage selectById(Long id);
    
    /**
     * 根据房源ID查询房源图片列表
     */
    List<HouseImage> selectByHouseId(Long houseId);
    
    /**
     * 根据房源ID查询封面图片
     */
    HouseImage selectCoverByHouseId(Long houseId);
    
    /**
     * 新增房源图片
     */
    int insert(HouseImage houseImage);
    
    /**
     * 批量新增房源图片
     */
    int insertBatch(List<HouseImage> houseImages);
    
    /**
     * 更新房源图片
     */
    int update(HouseImage houseImage);
    
    /**
     * 设置房源封面图片
     */
    int setCover(@Param("houseId") Long houseId, @Param("imageId") Long imageId);
    
    /**
     * 删除房源图片
     */
    int deleteById(Long id);
    
    /**
     * 根据房源ID删除房源图片
     */
    int deleteByHouseId(Long houseId);
}
13. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\StudentVerificationDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.StudentVerification;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 学生认证DAO接口
 */
@Mapper
public interface StudentVerificationDao {
    
    /**
     * 根据ID查询学生认证
     */
    StudentVerification selectById(Long id);
    
    /**
     * 根据用户ID查询学生认证
     */
    StudentVerification selectByUserId(Long userId);
    
    /**
     * 查询学生认证列表
     */
    List<StudentVerification> selectList(StudentVerification verification);
    
    /**
     * 新增学生认证
     */
    int insert(StudentVerification verification);
    
    /**
     * 更新学生认证
     */
    int update(StudentVerification verification);
    
    /**
     * 更新学生认证状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status, @Param("remark") String remark);
    
    /**
     * 删除学生认证
     */
    int deleteById(Long id);
}
14. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\LandlordVerificationDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.LandlordVerification;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 房东认证DAO接口
 */
@Mapper
public interface LandlordVerificationDao {
    
    /**
     * 根据ID查询房东认证
     */
    LandlordVerification selectById(Long id);
    
    /**
     * 根据用户ID查询房东认证
     */
    LandlordVerification selectByUserId(Long userId);
    
    /**
     * 查询房东认证列表
     */
    List<LandlordVerification> selectList(LandlordVerification verification);
    
    /**
     * 新增房东认证
     */
    int insert(LandlordVerification verification);
    
    /**
     * 更新房东认证
     */
    int update(LandlordVerification verification);
    
    /**
     * 更新房东认证状态
     */
    int updateStatus(@Param("id") Long id, @Param("status") Integer status, @Param("remark") String remark);
    
    /**
     * 删除房东认证
     */
    int deleteById(Long id);
}
15. File: d:\htsun\Docs\资料\文章\rental-system\backend\src\main\java\com\rental\dao\FavoriteDao.java

java
CopyInsert
package com.rental.dao;

import com.rental.entity.Favorite;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 收藏DAO接口
 */
@Mapper
public interface FavoriteDao {
    
    /**
     * 根据ID查询收藏
     */
    Favorite selectById(Long id);
    
    /**
     * 根据用户ID查询收藏列表
     */
    List<Favorite> selectByUserId(Long userId);
    
    /**
     * 根据用户ID和房源ID查询收藏
     */
    Favorite selectByUserIdAndHouseId(@Param("userId") Long userId, @Param("houseId") Long houseId);
    
    /**
     * 新增收藏
     */
    int insert(Favorite favorite);
    
    /**
     * 删除收藏
     */
    int deleteById(Long id);
    
    /**
     * 根据用户ID和房源ID删除收藏
     */
    int deleteByUserIdAndHouseId(@Param("userId") Long userId, @Param("houseId") Long houseId);
}
Frontend Files
16. File: d:\htsun\Docs\资料\文章\rental-system\frontend\src\views\house\Detail.vue

vue
CopyInsert
<template>
  <div class="house-detail-container">
    <!-- 头部导航 -->
    <div class="header">
      <div class="container">
        <div class="logo">大学生租房管理系统</div>
        <div class="nav">
          <router-link to="/home" class="nav-item">首页</router-link>
          <router-link to="/house/map" class="nav-item">地图找房</router-link>
          <router-link to="/news" class="nav-item">租房资讯</router-link>
        </div>
        <div class="user-info">
          <template v-if="isLogin">
            <el-dropdown @command="handleCommand">
              <span class="el-dropdown-link">
                {{ username }}<i class="el-icon-arrow-down el-icon--right"></i>
              </span>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item command="profile">个人中心</el-dropdown-item>
                <el-dropdown-item command="favorite">我的收藏</el-dropdown-item>
                <el-dropdown-item v-if="isAdmin" command="admin">管理后台</el-dropdown-item>
                <el-dropdown-item v-if="isLandlord" command="landlord">房源管理</el-dropdown-item>
                <el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </template>
          <template v-else>
            <router-link to="/login" class="login-btn">登录</router-link>
            <router-link to="/register" class="register-btn">注册</router-link>
          </template>
        </div>
      </div>
    </div>

    <!-- 房源详情内容 -->
    <div class="detail-content">
      <div class="container">
        <div class="house-title">
          <h1>{{ house.title }}</h1>
          <div class="house-tags">
            <span class="tag">{{ house.houseType }}</span>
            <span class="tag">{{ house.area }}</span>
            <span class="tag">{{ house.orientation }}</span>
            <span class="tag">{{ house.decoration }}</span>
          </div>
        </div>

        <div class="detail-main">
          <!-- 左侧图片 -->
          <div class="detail-left">
            <div class="house-images">
              <el-carousel height="400px">
                <el-carousel-item v-for="(image, index) in houseImages" :key="index">
                  <img :src="image.url" alt="房源图片">
                </el-carousel-item>
              </el-carousel>
            </div>
          </div>

          <!-- 右侧信息 -->
          <div class="detail-right">
            <div class="price-info">
              <div class="price">
                <span class="price-num">{{ house.price }}</span>
                <span class="price-unit">/</span>
              </div>
              <div class="price-tags">
                <span>押一付三</span>
                <span>{{ houseDetail.rentType }}</span>
              </div>
            </div>

            <div class="landlord-info">
              <div class="landlord-avatar">
                <img src="https://via.placeholder.com/60" alt="房东头像">
              </div>
              <div class="landlord-detail">
                <div class="landlord-name">{{ house.contact }}</div>
                <div class="landlord-phone">{{ house.contactPhone }}</div>
              </div>
              <el-button type="primary" @click="handleContact">联系房东</el-button>
            </div>

            <div class="action-buttons">
              <el-button type="primary" @click="handleAppointment">预约看房</el-button>
              <el-button :type="isFavorite ? 'danger' : 'info'" @click="handleFavorite">
                <i :class="isFavorite ? 'el-icon-star-on' : 'el-icon-star-off'"></i>
                {{ isFavorite ? '已收藏' : '收藏' }}
              </el-button>
            </div>
          </div>
        </div>

        <!-- 房源详情信息 -->
        <div class="detail-info">
          <el-tabs v-model="activeTab">
            <el-tab-pane label="房源信息" name="info">
              <div class="info-section">
                <h3>基本信息</h3>
                <div class="info-list">
                  <div class="info-item">
                    <span class="info-label">房源类型</span>
                    <span class="info-value">{{ houseDetail.houseCategory }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">户型</span>
                    <span class="info-value">{{ house.houseType }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">面积</span>
                    <span class="info-value">{{ house.area }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">楼层</span>
                    <span class="info-value">{{ house.floor }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">朝向</span>
                    <span class="info-value">{{ house.orientation }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">装修</span>
                    <span class="info-value">{{ house.decoration }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">电梯</span>
                    <span class="info-value">{{ houseDetail.hasElevator === 1 ? '有' : '无' }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">停车位</span>
                    <span class="info-value">{{ houseDetail.hasParking === 1 ? '有' : '无' }}</span>
                  </div>
                </div>
              </div>

              <div class="info-section">
                <h3>租金信息</h3>
                <div class="info-list">
                  <div class="info-item">
                    <span class="info-label">租金</span>
                    <span class="info-value">{{ house.price }}/</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">付款方式</span>
                    <span class="info-value">{{ houseDetail.paymentType }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">出租方式</span>
                    <span class="info-value">{{ houseDetail.rentType }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">最短租期</span>
                    <span class="info-value">{{ houseDetail.minRentPeriod }}个月</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">入住时间</span>
                    <span class="info-value">{{ formatDate(houseDetail.checkInTime) }}</span>
                  </div>
                </div>
              </div>

              <div class="info-section">
                <h3>费用信息</h3>
                <div class="info-list">
                  <div class="info-item">
                    <span class="info-label">水费</span>
                    <span class="info-value">{{ houseDetail.waterFee }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">电费</span>
                    <span class="info-value">{{ houseDetail.electricityFee }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">燃气费</span>
                    <span class="info-value">{{ houseDetail.gasFee }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">网费</span>
                    <span class="info-value">{{ houseDetail.internetFee }}</span>
                  </div>
                  <div class="info-item">
                    <span class="info-label">物业费</span>
                    <span class="info-value">{{ houseDetail.propertyFee }}</span>
                  </div>
                </div>
              </div>

              <div class="info-section">
                <h3>房源描述</h3>
                <div class="description">
                  {{ houseDetail.description }}
                </div>
              </div>

              <div class="info-section">
                <h3>配套设施</h3>
                <div class="facilities">
                  <el-tag v-for="(item, index) in facilitiesList" :key="index" size="medium">{{ item }}</el-tag>
                </div>
              </div>
            </el-tab-pane>

            <el-tab-pane label="位置交通" name="location">
              <div class="info-section">
                <h3>位置信息</h3>
                <div class="location-info">
                  <div class="address">
                    <span class="info-label">小区名称</span>
                    <span class="info-value">{{ house.community }}</span>
                  </div>
                  <div class="address">
                    <span class="info-label">详细地址</span>
                    <span class="info-value">{{ house.address }}</span>
                  </div>
                </div>
                <div class="map-container" id="map" style="height: 400px; margin-top: 20px;"></div>
              </div>

              <div class="info-section">
                <h3>交通情况</h3>
                <div class="transportation">
                  {{ houseDetail.transportation }}
                </div>
              </div>

              <div class="info-section">
                <h3>周边配套</h3>
                <div class="surroundings">
                  {{ houseDetail.surroundings }}
                </div>
              </div>
            </el-tab-pane>
          </el-tabs>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { getHouseDetail, getHouseImages } from '@/api/house';
import { addFavorite, cancelFavorite, checkFavorite } from '@/api/favorite';
import { mapGetters } from 'vuex';
import { formatDate } from '@/utils/date';

export default {
  name: 'HouseDetail',
  data() {
    return {
      house: {},
      houseDetail: {},
      houseImages: [],
      activeTab: 'info',
      isFavorite: false,
      facilitiesList: []
    };
  },
  computed: {
    ...mapGetters(['isLogin', 'username', 'userId', 'isAdmin', 'isLandlord']),
    houseId() {
      return this.$route.params.id;
    }
  },
  created() {
    this.fetchHouseDetail();
    this.fetchHouseImages();
    if (this.isLogin) {
      this.checkIsFavorite();
    }
  },
  methods: {
    formatDate,
    async fetchHouseDetail() {
      try {
        const res = await getHouseDetail(this.houseId);
        if (res.code === 200) {
          this.house = res.data.house;
          this.houseDetail = res.data.houseDetail;
          
          // 处理配套设施
          if (this.houseDetail.facilities) {
            this.facilitiesList = this.houseDetail.facilities.split(',');
          }
          
          // 加载地图
          this.$nextTick(() => {
            this.initMap();
          });
        }
      } catch (error) {
        this.$message.error('获取房源详情失败');
        console.error(error);
      }
    },
    async fetchHouseImages() {
      try {
        const res = await getHouseImages(this.houseId);
        if (res.code === 200) {
          this.houseImages = res.data;
        }
      } catch (error) {
        this.$message.error('获取房源图片失败');
        console.error(error);
      }
    },
    async checkIsFavorite() {
      try {
        const res = await checkFavorite(this.houseId);
        if (res.code === 200) {
          this.isFavorite = res.data;
        }
      } catch (error) {
        console.error(error);
      }
    },
    async handleFavorite() {
      if (!this.isLogin) {
        this.$message.warning('请先登录');
        this.$router.push(`/login?redirect=/house/detail/${this.houseId}`);
        return;
      }
      
      try {
        if (this.isFavorite) {
          const res = await cancelFavorite(this.houseId);
          if (res.code === 200) {
            this.isFavorite = false;
            this.$message.success('取消收藏成功');
          }
        } else {
          const res = await addFavorite(this.houseId);
          if (res.code === 200) {
            this.isFavorite = true;
            this.$message.success('收藏成功');
          }
        }
      } catch (error) {
        this.$message.error('操作失败');
        console.error(error);
      }
    },
    handleContact() {
      if (!this.isLogin) {
        this.$message.warning('请先登录');
        this.$router.push(`/login?redirect=/house/detail/${this.houseId}`);
        return;
      }
      
      this.$alert(`联系人:${this.house.contact}<br/>联系电话:${this.house.contactPhone}`, '联系房东', {
        dangerouslyUseHTMLString: true,
        confirmButtonText: '确定'
      });
    },
    handleAppointment() {
      if (!this.isLogin) {
        this.$message.warning('请先登录');
        this.$router.push(`/login?redirect=/house/detail/${this.houseId}`);
        return;
      }
      
      this.$message.info('预约功能即将上线,敬请期待');
    },
    initMap() {
      // 此处为地图初始化代码,需要引入地图API
      // 例如使用百度地图或高德地图
      console.log('初始化地图,经度:', this.house.longitude, '纬度:', this.house.latitude);
    },
    handleCommand(command) {
      switch (command) {
        case 'profile':
          this.$router.push('/user/profile');
          break;
        case 'favorite':
          this.$router.push('/user/favorite');
          break;
        case 'admin':
          this.$router.push('/admin');
          break;
        case 'landlord':
          this.$router.push('/landlord');
          break;
        case 'logout':
          this.$store.dispatch('logout');
          this.$router.push('/login');
          break;
      }
    }
  }
};
</script>

<style scoped>
.house-detail-container {
  min-height: 100vh;
  background-color: #f5f5f5;
}

.header {
  background-color: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  position: sticky;
  top: 0;
  z-index: 100;
}

.header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
  padding: 0 20px;
  max-width: 1200px;
  margin: 0 auto;
}

.logo {
  font-size: 20px;
  font-weight: bold;
  color: #409EFF;
}

.nav {
  display: flex;
}

.nav-item {
  margin: 0 15px;
  color: #333;
  text-decoration: none;
}

.nav-item:hover {
  color: #409EFF;
}

.user-info {
  display: flex;
  align-items: center;
}

.login-btn, .register-btn {
  padding: 5px 15px;
  margin-left: 10px;
  border-radius: 4px;
  text-decoration: none;
}

.login-btn {
  color: #409EFF;
}

.register-btn {
  background-color: #409EFF;
  color: #fff;
}

.detail-content {
  padding: 20px 0;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

.house-title {
  margin-bottom: 20px;
}

.house-title h1 {
  font-size: 24px;
  margin-bottom: 10px;
}

.house-tags {
  display: flex;
  flex-wrap: wrap;
}

.tag {
  background-color: #f0f9ff;
  color: #409EFF;
  padding: 2px 8px;
  margin-right: 10px;
  border-radius: 4px;
  font-size: 12px;
}

.detail-main {
  display: flex;
  margin-bottom: 30px;
}

.detail-left {
  flex: 2;
  margin-right: 20px;
}

.detail-right {
  flex: 1;
  background-color: #fff;
  padding: 20px;
  border-radius: 4px;
}

.price-info {
  margin-bottom: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid #eee;
}

.price {
  display: flex;
  align-items: baseline;
  margin-bottom: 10px;
}

.price-num {
  font-size: 28px;
  color: #ff5a5f;
  font-weight: bold;
}

.price-unit {
  font-size: 14px;
  color: #666;
  margin-left: 5px;
}

.price-tags span {
  background-color: #fff5f5;
  color: #ff5a5f;
  padding: 2px 8px;
  margin-right: 10px;
  border-radius: 4px;
  font-size: 12px;
}

.landlord-info {
  display: flex;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid #eee;
}

.landlord-avatar {
  margin-right: 15px;
}

.landlord-avatar img {
  width: 60px;
  height: 60px;
  border-radius: 50%;
}

.landlord-detail {
  flex: 1;
}

.landlord-name {
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 5px;
}

.landlord-phone {
  color: #666;
}

.action-buttons {
  display: flex;
  justify-content: space-between;
}

.detail-info {
  background-color: #fff;
  padding: 20px;
  border-radius: 4px;
}

.info-section {
  margin-bottom: 30px;
}

.info-section h3 {
  font-size: 18px;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

.info-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 15px;
}

.info-item {
  display: flex;
}

.info-label {
  color: #666;
  margin-right: 10px;
  min-width: 70px;
}

.info-value {
  color: #333;
  font-weight: 500;
}

.description, .transportation, .surroundings {
  line-height: 1.8;
  color: #333;
}

.facilities {
  display: flex;
  flex-wrap: wrap;
}

.facilities .el-tag {
  margin-right: 10px;
  margin-bottom: 10px;
}

.location-info {
  margin-bottom: 15px;
}

.address {
  margin-bottom: 10px;
}
</style>
API Service Files
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值