1. 租房管理系统全栈开发实战
这套基于SpringBoot+Vue+MySQL的租房管理系统源码,是我在2021年实际交付给某长租公寓平台的核心系统简化版。相比市面上那些demo级的教学项目,这套系统完整实现了租客管理、合同管理、收付款等核心业务闭环,特别适合需要快速搭建业务系统的中小型房产中介或二房东群体。
系统采用经典的前后端分离架构,后端基于SpringBoot 2.7提供RESTful API,前端使用Vue 2.6+ElementUI构建管理后台,数据库采用MySQL 8.0。所有组件都选用当前企业开发中的主流稳定版本,避免了新版本潜在的兼容性问题。最关键是整套代码开箱即用,我已经移除了所有客户敏感信息,但保留了完整的权限控制、日志记录等企业级功能模块。
提示:系统默认集成了阿里云OSS文件上传和支付宝沙箱支付,实际部署时需要替换为自己的配置。我在代码中用TODO标记了所有需要修改的位置。
1.1 技术栈选型解析
后端技术栈:
- SpringBoot 2.7.3:简化配置,内置Tomcat 9.0
- MyBatis-Plus 3.5.1:避免重复CRUD代码
- Hutool 5.8.5:处理各种Java工具类需求
- JWT 0.9.1:实现无状态认证
- Lombok 1.18.24:自动生成getter/setter
前端技术栈:
- Vue 2.6.14:稳定易用的主流版本
- ElementUI 2.15.8:管理后台经典UI框架
- Axios 0.27.2:处理HTTP请求
- Vue-router 3.5.1:前端路由控制
- ECharts 5.3.2:数据可视化展示
这套组合的突出优势是:
- 开发效率高:MyBatis-Plus可节省约40%的DAO层代码
- 学习成本低:ElementUI文档完善,组件丰富
- 性能有保障:SpringBoot+MyBatis组合可支撑2000+TPS
- 易于扩展:清晰的模块划分方便新增功能
2. 系统核心模块实现
2.1 数据库设计要点
MySQL表结构设计遵循了几个关键原则:
- 所有表必须包含create_time/update_time字段
- 金额字段统一使用DECIMAL(12,2)类型
- 状态字段使用TINYINT而非VARCHAR
- 建立合理的索引但避免过度索引
核心表关系如下:
| 表名 | 关键字段 | 索引设计 |
|---|---|---|
| sys_user | username,phone,password | 唯一索引:username |
| house_info | title,address,price,status | 联合索引:address+status |
| contract | house_id,tenant_id,start_date | 外键索引:house_id |
| payment_record | contract_id,amount,payment_method | 普通索引:contract_id |
踩坑提醒:当初在payment_record表没有加contract_id索引,导致对账查询时出现全表扫描。后来通过explain分析SQL后增加了索引,查询速度从3.2秒提升到0.05秒。
2.2 后端关键代码解析
租约到期自动提醒实现:
java复制// 使用Spring Scheduled实现定时任务
@Scheduled(cron = "0 0 9 * * ?") // 每天上午9点执行
public void checkContractExpiration() {
LocalDate warningDate = LocalDate.now().plusDays(7);
List<Contract> expiringContracts = contractMapper.selectList(
new QueryWrapper<Contract>()
.le("end_date", warningDate)
.eq("status", 1) // 1表示生效中
);
expiringContracts.forEach(contract -> {
String message = String.format("合同%s将于%s到期",
contract.getContractNo(),
contract.getEndDate());
smsService.send(contract.getTenantPhone(), message);
});
}
这段代码体现了几个最佳实践:
- 使用MyBatis-Plus的QueryWrapper构建条件查询
- 日期处理采用Java 8的LocalDate
- 业务消息使用模板字符串构建
- 将短信服务抽象成独立Service
2.3 前端复杂表单处理
房源信息编辑页需要处理图片上传、多级联动等复杂场景:
vue复制<template>
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="所在城市" prop="cityCode">
<el-cascader
v-model="form.cityCode"
:options="cityOptions"
@change="handleCityChange"
/>
</el-form-item>
<el-form-item label="房源图片">
<el-upload
action="/api/upload"
list-type="picture-card"
:file-list="fileList"
:on-success="handleUploadSuccess"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
cityCode: []
},
rules: {
cityCode: [
{ required: true, message: '请选择城市', trigger: 'blur' }
]
}
}
},
methods: {
handleUploadSuccess(response) {
this.form.imageUrls.push(response.data.url)
}
}
}
</script>
这个组件解决了三个典型问题:
- 使用ElementUI的Cascader实现省市区三级联动
- 图片上传与表单数据绑定
- 通过rules实现表单验证
3. 系统部署实战
3.1 环境准备清单
服务器最低配置:
- CPU:2核(建议4核)
- 内存:4GB(建议8GB)
- 磁盘:50GB(系统盘)+ 100GB(数据盘)
- 操作系统:CentOS 7.6+
软件版本要求:
- JDK 1.8(必须Oracle JDK)
- MySQL 8.0(建议8.0.26+)
- Node.js 14.x(不要用16+,ElementUI可能有兼容问题)
- Nginx 1.18+(用于前端部署和反向代理)
3.2 后端部署关键步骤
- 数据库初始化:
bash复制mysql -uroot -p < docs/sql/init.sql
mysql -uroot -p < docs/sql/data_demo.sql
- 修改应用配置:
yaml复制# application-prod.yml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/rent_db?useSSL=false
username: rent_user
password: Rent@1234
redis:
host: 127.0.0.1
port: 6379
- 打包并运行:
bash复制mvn clean package -DskipTests
nohup java -jar target/rent-manage-1.0.0.jar > app.log 2>&1 &
3.3 前端部署注意事项
- 环境变量配置:
env复制# .env.production
VUE_APP_BASE_API = '/api'
VUE_APP_OSS_PATH = 'https://your-oss-endpoint'
- 构建优化建议:
bash复制# 安装依赖时使用国内源
npm install --registry=https://registry.npm.taobao.org
# 构建生产环境代码
npm run build:prod
# 生成的dist目录部署到Nginx
- Nginx关键配置:
nginx复制location /api {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
location / {
root /home/rent/frontend/dist;
try_files $uri $uri/ /index.html;
}
4. 典型问题排查指南
4.1 跨域问题解决方案
当出现403跨域错误时,按以下步骤检查:
- 确保SpringBoot已配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.maxAge(3600);
}
}
- 检查Nginx是否添加了CORS头:
nginx复制add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
- 如果使用JWT认证,需要额外处理OPTIONS请求:
java复制@Component
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
// ...其他JWT验证逻辑
}
}
4.2 性能优化实战记录
问题现象:房源列表页在数据量达到5000条时,查询耗时超过8秒
排查过程:
- 使用Arthas监控发现SQL执行时间过长
- 通过EXPLAIN分析发现缺少复合索引
- 确认前端没有做分页加载
解决方案:
- 数据库层面:
sql复制ALTER TABLE house_info
ADD INDEX idx_search (status, price, area);
- 后端改进:
java复制public PageResult<HouseVO> queryHouses(HouseQuery query) {
Page<HouseInfo> page = new Page<>(query.getPageNum(), query.getPageSize());
IPage<HouseInfo> iPage = houseMapper.selectPage(page,
new QueryWrapper<HouseInfo>()
.eq(query.getStatus() != null, "status", query.getStatus())
.orderByAsc("price"));
return PageResult.success(iPage);
}
- 前端增加分页控件:
vue复制<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="query.pageNum"
:page-sizes="[10, 20, 50]"
:page-size="query.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
优化后效果:相同数据量下查询时间降至120ms左右,内存占用减少70%
5. 二次开发建议
对于需要扩展功能的开发者,推荐从以下几个方向入手:
- 智能合约审核:
java复制// 在ContractService中添加AI审核逻辑
public void reviewContract(Contract contract) {
// 调用NLP服务分析合同文本
AiReviewResult result = aiService.reviewText(contract.getContent());
if (result.getRiskScore() > 0.7) {
contract.setStatus(ContractStatus.REVIEW_REJECTED);
contract.setRejectReason(result.getRiskReason());
} else {
contract.setStatus(ContractStatus.REVIEW_APPROVED);
}
contractMapper.updateById(contract);
}
- 微信小程序集成:
- 使用uni-app重构前端代码
- 对接微信登录和支付接口
- 实现扫码查看房源功能
- 数据统计分析:
sql复制-- 每月租金收入统计
SELECT
DATE_FORMAT(pay_time,'%Y-%m') AS month,
SUM(amount) AS total_amount
FROM payment_record
WHERE payment_type = 'RENT'
GROUP BY DATE_FORMAT(pay_time,'%Y-%m')
ORDER BY month DESC;
这套系统在我实际交付的客户中,最受欢迎的功能其实是自动生成合同模板和租金到期提醒。有个客户反馈说,使用系统后他们的租金收缴率从82%提升到了97%,因为系统会自动发送三次提醒:到期前7天、3天和当天。
