1. 项目概述:基于SSM框架的房屋租赁管理系统实战
作为一名有多年Java开发经验的程序员,我最近完成了一个基于SSM框架的房屋租赁管理系统。这个项目采用了Spring+SpringMVC+MyBatis的核心技术栈,并整合了MyBatis-Plus作为数据访问增强工具。系统实现了租客、房东和管理员三类角色的全流程租赁业务管理,包括房屋发布、搜索、预订、合同签订、订单管理等核心功能。
在实际开发过程中,我发现这个系统特别适合作为Java Web开发的实战项目,因为它涵盖了企业级应用开发中的大部分典型场景:用户权限管理、数据校验、定时任务、文件上传等。同时,系统的业务逻辑清晰,但又足够复杂,能够帮助开发者全面掌握SSM框架的实际应用。
2. 技术栈选型与架构设计
2.1 技术栈详解
在项目启动阶段,我经过仔细评估选择了以下技术组合:
-
核心框架:Spring 5 + SpringMVC + MyBatis 3
- Spring提供了强大的IoC和AOP支持
- SpringMVC处理Web层请求和响应
- MyBatis作为ORM框架管理数据库交互
-
数据访问增强:MyBatis-Plus 3.4.0
- 提供了BaseMapper等便捷接口
- 内置通用CRUD方法,减少重复代码
- 支持Lambda表达式查询
-
数据库连接池:Druid 1.2.6
- 阿里巴巴开源的数据库连接池
- 提供监控统计功能
- 支持SQL防注入
-
前端技术:
- JSP作为视图层技术
- Bootstrap 4构建响应式界面
- jQuery处理前端交互
- ECharts用于数据可视化
-
辅助工具:
- Hutool:Java工具类库
- FastJSON:高性能JSON处理
- JavaMail:邮件发送功能
- Lombok:简化POJO编写
提示:在实际项目中,建议使用Maven或Gradle管理这些依赖,确保版本兼容性。我遇到过因为版本冲突导致的奇怪问题,花费了大量时间排查。
2.2 分层架构设计
系统采用经典的四层架构设计,各层职责明确:
2.2.1 表现层(Controller)
- 分为前台(front)和后台(backend)两个包
- 使用@Controller注解标记控制器类
- 通过@RequestMapping定义请求映射
- 返回JSON数据使用@RestController
java复制@Controller
@RequestMapping("/front/house")
public class FrontHouseController {
@Autowired
private IHouseService houseService;
@GetMapping("/search")
public String searchHouse(Model model, HouseSearchVO searchVO) {
Page<House> page = houseService.searchHouses(searchVO);
model.addAttribute("page", page);
return "front/house_list";
}
}
2.2.2 业务层(Service)
- 定义接口和实现类分离
- 使用@Service注解标记服务类
- 通过@Transactional管理事务
- 基于BaseService提供通用CRUD能力
java复制public interface IHouseService extends IService<House> {
Page<House> searchHouses(HouseSearchVO searchVO);
boolean publishHouse(HousePublishVO publishVO, Long userId);
boolean auditHouse(Long houseId, Integer auditStatus);
}
@Service
public class HouseServiceImpl extends ServiceImpl<HouseMapper, House>
implements IHouseService {
// 具体实现...
}
2.2.3 数据访问层(Mapper)
- 接口继承MyBatis-Plus的BaseMapper
- 使用@Mapper注解或@Repository注解
- 支持自定义XML映射文件
- 提供灵活的查询方法
java复制@Mapper
public interface HouseMapper extends BaseMapper<House> {
@Select("SELECT * FROM t_house WHERE status = #{status}")
List<House> selectByStatus(@Param("status") Integer status);
}
2.2.4 实体层(Entity)
- 使用@Data注解(Lombok)
- 继承BaseEntity包含公共字段
- 使用@TableName指定表名
- 字段使用@TableField映射
java复制@Data
@TableName("t_house")
public class House extends BaseEntity {
@TableField("title")
private String title;
@TableField("rent_price")
private BigDecimal rentPrice;
// 其他字段...
}
3. 核心功能模块实现
3.1 用户管理模块
3.1.1 用户注册与登录
用户注册流程实现了以下关键点:
- 前端表单验证(使用jQuery Validation)
- 后端参数校验(使用Hibernate Validator)
- 用户名唯一性检查
- 密码加密存储(使用BCrypt)
- 初始角色分配
java复制@PostMapping("/register")
public Result register(@Valid UserRegisterVO registerVO) {
// 检查用户名是否已存在
if (userService.checkUsernameExists(registerVO.getUsername())) {
return Result.error("用户名已存在");
}
// 密码加密
String encodedPwd = BCrypt.hashpw(registerVO.getPassword(), BCrypt.gensalt());
// 创建用户
User user = new User();
user.setUsername(registerVO.getUsername());
user.setPassword(encodedPwd);
user.setRole(registerVO.getRole()); // 1-租客 2-房东 3-管理员
return userService.save(user) ? Result.success() : Result.error("注册失败");
}
登录功能实现了:
- 账号密码验证
- 生成JWT token
- 记录登录日志
- 根据角色跳转不同首页
注意:在实际部署时,一定要配置HTTPS保护用户凭证传输安全。我曾经遇到过中间人攻击导致用户信息泄露的情况。
3.1.2 权限控制系统
系统采用基于角色的访问控制(RBAC)模型:
- 定义三种角色:租客、房东、管理员
- 使用拦截器验证权限
- 注解方式声明接口权限要求
java复制@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
int[] value() default {}; // 允许的角色类型
}
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 获取注解信息
RequireRole annotation = ((HandlerMethod)handler)
.getMethodAnnotation(RequireRole.class);
if (annotation != null) {
// 验证用户角色是否匹配
User user = getCurrentUser(request);
if (!ArrayUtils.contains(annotation.value(), user.getRole())) {
response.sendError(403, "无权访问");
return false;
}
}
return true;
}
}
3.2 房屋管理模块
3.2.1 房屋发布流程
房东发布房屋的核心流程:
- 表单填写(带实时预览)
- 图片上传(限制大小和类型)
- 数据校验(前端+后端)
- 保存到数据库(状态为待审核)
- 通知管理员审核
关键代码实现:
java复制@PostMapping("/publish")
@RequireRole(Role.LANDLORD)
public Result publishHouse(@Valid HousePublishVO publishVO) {
// 获取当前用户ID
Long userId = getCurrentUserId();
// 处理图片上传
List<String> imageUrls = new ArrayList<>();
for (MultipartFile file : publishVO.getImages()) {
String url = fileService.upload(file);
imageUrls.add(url);
}
// 构建房屋实体
House house = new House();
BeanUtils.copyProperties(publishVO, house);
house.setLandlordId(userId);
house.setStatus(HouseStatus.PENDING_AUDIT);
house.setImages(StringUtils.join(imageUrls, ","));
// 保存到数据库
return houseService.save(house)
? Result.success()
: Result.error("发布失败");
}
3.2.2 房屋搜索功能
搜索功能支持多条件筛选:
- 城市/区域选择
- 价格区间滑块
- 面积范围
- 房屋类型(整租/合租)
- 配套设施(电梯、暖气等)
- 分页支持
后端实现使用MyBatis-Plus的Wrapper构建动态查询:
java复制@Override
public Page<House> searchHouses(HouseSearchVO searchVO) {
// 构建查询条件
LambdaQueryWrapper<House> wrapper = Wrappers.lambdaQuery();
wrapper.eq(House::getStatus, HouseStatus.ON_SHELF);
if (StringUtils.isNotBlank(searchVO.getCity())) {
wrapper.eq(House::getCity, searchVO.getCity());
}
if (searchVO.getMinPrice() != null) {
wrapper.ge(House::getRentPrice, searchVO.getMinPrice());
}
if (searchVO.getMaxPrice() != null) {
wrapper.le(House::getRentPrice, searchVO.getMaxPrice());
}
// 其他条件...
// 执行分页查询
return houseMapper.selectPage(
new Page<>(searchVO.getPage(), searchVO.getSize()),
wrapper
);
}
3.3 订单管理模块
3.3.1 订单创建流程
订单创建涉及多个业务校验:
- 检查房屋是否可租
- 验证租期合法性(最小7天)
- 计算总租金(租金×租期)
- 生成合同模板
- 创建初始订单(状态为待签合同)
java复制@PostMapping("/create")
@RequireRole(Role.TENANT)
public Result createOrder(@Valid OrderCreateVO createVO) {
// 验证房屋状态
House house = houseService.getById(createVO.getHouseId());
if (house == null || house.getStatus() != HouseStatus.ON_SHELF) {
return Result.error("房屋不可租");
}
// 验证租期
long days = ChronoUnit.DAYS.between(
createVO.getStartDate(),
createVO.getEndDate()
);
if (days < 7) {
return Result.error("最短租期为7天");
}
// 计算总租金
BigDecimal totalAmount = house.getRentPrice()
.multiply(new BigDecimal(days / 30.0));
// 创建订单
Order order = new Order();
order.setHouseId(createVO.getHouseId());
order.setTenantId(getCurrentUserId());
order.setLandlordId(house.getLandlordId());
order.setStartDate(createVO.getStartDate());
order.setEndDate(createVO.getEndDate());
order.setTotalAmount(totalAmount);
order.setStatus(OrderStatus.WAITING_SIGN);
return orderService.save(order)
? Result.success(order.getId())
: Result.error("创建订单失败");
}
3.3.2 定时任务处理
系统使用Spring Scheduler处理到期订单:
- 每分钟检查一次到期订单
- 自动更新订单状态为"已退租"
- 重置房屋状态为"可出租"
- 记录操作日志
java复制@Scheduled(cron = "0 * * * * ?")
public void processExpiredOrders() {
// 查询今天到期的订单
LambdaQueryWrapper<Order> wrapper = Wrappers.lambdaQuery();
wrapper.eq(Order::getStatus, OrderStatus.IN_EFFECT)
.le(Order::getEndDate, LocalDate.now());
List<Order> orders = orderService.list(wrapper);
// 批量处理
orders.forEach(order -> {
// 更新订单状态
order.setStatus(OrderStatus.COMPLETED);
orderService.updateById(order);
// 更新房屋状态
House house = houseService.getById(order.getHouseId());
house.setStatus(HouseStatus.ON_SHELF);
houseService.updateById(house);
// 记录日志
logService.save(new Log(
"系统自动处理到期订单",
"订单ID: " + order.getId()
));
});
}
4. 系统部署与优化
4.1 生产环境部署建议
在实际部署时,我推荐以下配置:
-
服务器配置:
- Linux服务器(CentOS/Ubuntu)
- JDK 1.8+
- Tomcat 9+ 或使用Spring Boot内嵌容器
- MySQL 5.7+ 配置主从复制
-
性能优化:
- 启用Druid监控:http://localhost:8080/druid
- 配置MyBatis二级缓存
- 对高频查询添加Redis缓存
- 静态资源使用CDN加速
-
安全措施:
- 配置HTTPS证书
- 启用Druid的SQL防火墙
- 定期备份数据库
- 实现操作日志审计
4.2 常见问题排查
在开发过程中,我遇到过以下典型问题及解决方案:
-
MyBatis-Plus主键冲突:
- 现象:批量插入时出现主键重复
- 原因:默认的ID生成策略是雪花算法,但服务器时间回拨会导致冲突
- 解决:配置自定义ID生成器或使用数据库自增主键
-
事务失效问题:
- 现象:@Transactional注解不生效
- 原因:可能是方法内部调用或异常类型不匹配
- 解决:确保异常是RuntimeException,且方法由Spring代理调用
-
文件上传大小限制:
- 现象:上传大文件时报错
- 原因:SpringMVC默认限制文件大小
- 解决:配置multipart.maxFileSize和maxRequestSize
properties复制# application.properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=20MB
- 跨域问题:
- 现象:前端请求被浏览器拦截
- 解决:添加CORS配置或使用Nginx反向代理
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
5. 项目扩展方向
这个基础系统还可以进一步扩展以下功能:
-
支付集成:
- 对接支付宝/微信支付接口
- 实现租金在线支付
- 增加支付记录和退款功能
-
消息通知:
- 集成短信通知(阿里云短信)
- 实现站内信系统
- 增加WebSocket实时通知
-
数据分析:
- 使用ECharts展示租赁数据统计
- 生成房东收益报表
- 分析热门房源特征
-
移动端适配:
- 开发微信小程序版本
- 实现APP接口
- 优化移动端用户体验
-
智能推荐:
- 基于用户行为推荐房源
- 实现相似房源推荐
- 个性化搜索排序
在实际开发中,我建议采用迭代开发的方式,先实现核心功能,再逐步添加这些扩展功能。每个迭代周期控制在2-3周,确保系统稳定演进。