这套前后端分离的小区管理系统是我在参与多个智慧社区项目后总结出的最佳实践方案。传统单体架构的小区管理系统存在维护困难、扩展性差等问题,而采用SpringBoot+Vue的分离架构能有效解决这些痛点。
系统核心功能包括:
提示:系统采用RBAC权限模型,预设了超级管理员、物业管理员、普通住户三种角色,权限粒度细化到按钮级别。
SpringBoot 2.7.x 作为基础框架,主要考虑因素:
数据库操作采用 MyBatis-Plus 3.5.x 而非原生MyBatis,因为:
java复制// 典型Service层实现示例
@Service
public class ResidentServiceImpl extends ServiceImpl<ResidentMapper, Resident>
implements ResidentService {
@Override
public Page<ResidentVO> getPage(ResidentQueryDTO dto) {
return lambdaQuery()
.like(StringUtils.isNotBlank(dto.getName()), Resident::getName, dto.getName())
.eq(dto.getBuildingId() != null, Resident::getBuildingId, dto.getBuildingId())
.page(dto.toPage())
.convert(this::toVO);
}
}
Vue 3 + TypeScript 组合的优势:
前端工程化关键配置:
javascript复制// vite.config.ts 优化配置
export default defineConfig({
plugins: [vue()],
build: {
chunkSizeWarningLimit: 1500,
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
})
MySQL 8.0版本选择依据:
核心表关系设计:
mermaid复制erDiagram
RESIDENT ||--o{ PROPERTY_FEE : "1:n"
RESIDENT ||--o{ REPAIR_ORDER : "1:n"
RESIDENT {
int resident_id PK
varchar(50) name
varchar(20) phone
varchar(100) address
}
PROPERTY_FEE {
int fee_id PK
int resident_id FK
decimal(10,2) amount
varchar(20) status
}
批量导入实现要点:
java复制@PostMapping("/import")
public R<String> importResidents(@RequestParam MultipartFile file) {
String taskId = UUID.randomUUID().toString();
redisLock.lock("import:resident", taskId, 30, TimeUnit.MINUTES);
residentImportService.asyncImport(file, taskId);
return R.success(taskId);
}
分页查询优化方案:
selectPage方法building_id和unit_no联合索引支付流程设计:
java复制// 支付状态回调处理
@Transactional
public void handlePaymentNotify(PaymentNotifyDTO dto) {
PropertyFee fee = getById(dto.getOutTradeNo());
if (fee.getStatus() == PaymentStatus.PAID) {
return;
}
fee.setStatus(PaymentStatus.PAID);
fee.setPaymentTime(LocalDateTime.now());
updateById(fee);
// 记录支付日志
paymentLogService.save(buildLog(fee, dto));
}
状态机设计:
java复制public enum RepairStatus {
PENDING("待处理") {
public boolean canTransferTo(RepairStatus status) {
return status == PROCESSING || status == REJECTED;
}
},
PROCESSING("处理中") {
public boolean canTransferTo(RepairStatus status) {
return status == COMPLETED || status == CANCELLED;
}
},
// 其他状态...
}
工单分配策略:
生产环境推荐配置:
bash复制-Xms2g -Xmx2g -XX:MaxMetaspaceSize=512m
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
nginx复制upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
}
}
性能优化方案:
bash复制# 生产环境构建命令
npm run build -- --mode production
高可用方案:
sql复制-- 索引优化示例
ALTER TABLE property_fee
ADD INDEX idx_resident_status (resident_id, payment_status);
开发环境配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.maxAge(3600);
}
}
生产环境推荐:
必备安全措施:
java复制@PreAuthorize("hasRole('ADMIN') or #dto.residentId == authentication.principal.id")
@PostMapping("/update")
public R<Void> updateResident(@Valid @RequestBody ResidentUpdateDTO dto) {
// ...
}
缓存策略示例:
java复制@Cacheable(value = "resident", key = "#id", unless = "#result == null")
public ResidentVO getResidentById(Long id) {
return baseMapper.selectResidentWithDetail(id);
}
SQL优化案例:
sql复制-- 优化前(全表扫描)
SELECT * FROM property_fee WHERE YEAR(payment_time) = 2023;
-- 优化后(索引扫描)
SELECT * FROM property_fee
WHERE payment_time BETWEEN '2023-01-01' AND '2023-12-31 23:59:59';
移动端适配:开发微信小程序版本
数据大屏:接入ECharts实现
智能预警:
java复制// 定时任务示例
@Scheduled(cron = "0 0 9 * * ?")
public void sendPaymentReminder() {
List<Resident> residents = residentMapper.selectUnpaidResidents();
residents.forEach(resident -> {
smsService.send(resident.getPhone(), buildReminderContent(resident));
});
}