1. 项目背景与核心架构解析
尚庭公寓作为尚硅谷Java课程体系中的经典实战项目,是一个典型的B/S架构租房管理系统。这个项目之所以被选为教学案例,是因为它完整覆盖了企业级Java开发的核心技术栈,同时业务场景又足够贴近生活实际。
项目采用分层架构设计,主要分为:
- 表现层:基于Spring MVC实现RESTful API
- 业务层:Spring框架核心逻辑处理
- 数据访问层:MyBatis Plus进行数据库操作
- 基础设施层:Redis缓存、RabbitMQ消息队列等
技术选型上特别考虑了教学场景的需求:
- 使用Spring Boot简化配置,让学员快速上手
- 集成MyBatis Plus而非原生MyBatis,减少样板代码
- 前端采用Vue.js实现前后端分离
- 数据库使用MySQL 8.0,支持JSON字段等新特性
教学提示:项目特意保留了部分"不完美"设计,比如故意在几个Controller中混入了业务逻辑,这是为了让学员在代码审查环节能够发现问题并重构。
2. 开发环境搭建要点
2.1 基础环境配置
推荐使用以下环境组合:
- JDK 17(LTS版本)
- IntelliJ IDEA 2023.2+(社区版即可)
- MySQL 8.0.33+
- Redis 6.2+
- Node.js 16.x(前端开发需要)
环境变量配置常见问题解决方案:
bash复制# 检查Java版本
java -version
# 若显示非17版本,需检查JAVA_HOME设置
export JAVA_HOME=/path/to/jdk-17
export PATH=$JAVA_HOME/bin:$PATH
2.2 项目导入注意事项
- 使用IDEA导入时选择"Open"而非"Import Project"
- Maven依赖下载慢的解决方案:
xml复制<!-- settings.xml中添加阿里云镜像 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
- Lombok插件必须安装并启用,否则会报编译错误:
code复制java: You aren't using a compiler supported by lombok...
3. 核心业务模块实现
3.1 房源管理模块
采用DDD领域驱动设计思想,关键类包括:
- Apartment(聚合根)
- Room(实体)
- Address(值对象)
数据库设计要点:
sql复制CREATE TABLE `apartment` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`address_json` json DEFAULT NULL, -- 使用JSON类型存储复杂地址结构
`facilities` json DEFAULT NULL, -- 设施配置
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 租约管理模块
实现状态模式处理租约生命周期:
java复制public interface LeaseState {
void sign(LeaseContext context);
void terminate(LeaseContext context);
void renew(LeaseContext context);
}
// 具体状态实现
public class PendingState implements LeaseState {
@Override
public void sign(LeaseContext context) {
context.setState(new ActiveState());
// 生成电子合同等业务逻辑...
}
}
3.3 支付系统集成
采用策略模式支持多种支付方式:
java复制public interface PaymentStrategy {
PaymentResult pay(BigDecimal amount, PaymentRequest request);
}
@Service
@RequiredArgsConstructor
public class PaymentService {
private final Map<String, PaymentStrategy> strategies;
public PaymentResult processPayment(String type, BigDecimal amount) {
PaymentStrategy strategy = strategies.get(type);
if(strategy == null) {
throw new IllegalArgumentException("Unsupported payment type");
}
return strategy.pay(amount, new PaymentRequest());
}
}
4. 典型问题排查指南
4.1 跨域问题解决方案
前后端分离开发时常见的CORS问题:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("*")
.allowCredentials(true);
}
}
4.2 MyBatis Plus乐观锁冲突
实体类配置:
java复制public class BaseEntity {
@Version
private Integer version;
}
服务层处理:
java复制@Transactional
public void updateApartment(Apartment apartment) {
int result = apartmentMapper.updateById(apartment);
if(result == 0) {
throw new OptimisticLockingFailureException("数据已被其他用户修改");
}
}
4.3 Redis缓存穿透防护
使用布隆过滤器方案:
java复制public Apartment getApartmentById(Long id) {
// 1. 先查布隆过滤器
if(!bloomFilter.mightContain(id)) {
return null;
}
// 2. 查缓存
String key = "apartment:" + id;
Apartment apartment = redisTemplate.opsForValue().get(key);
if(apartment == null) {
// 3. 查数据库
apartment = apartmentMapper.selectById(id);
if(apartment != null) {
redisTemplate.opsForValue().set(key, apartment, 30, TimeUnit.MINUTES);
} else {
// 空值缓存防止穿透
redisTemplate.opsForValue().set(key, new Apartment(), 5, TimeUnit.MINUTES);
}
}
return apartment;
}
5. 项目扩展与优化方向
5.1 微服务化改造
建议拆分方向:
- 用户服务(account-service)
- 房源服务(apartment-service)
- 合约服务(contract-service)
- 支付服务(payment-service)
使用Spring Cloud Alibaba技术栈:
- Nacos服务发现
- Sentinel流量控制
- Seata分布式事务
5.2 性能优化实践
- SQL优化案例:
sql复制-- 优化前
SELECT * FROM apartment WHERE status = 1 ORDER BY create_time DESC;
-- 优化后
SELECT id,name,cover_image FROM apartment
WHERE status = 1 AND is_deleted = 0
ORDER BY create_time DESC LIMIT 20;
- 接口响应缓存:
java复制@Cacheable(value = "apartmentList", key = "#root.methodName + '_' + #page + '_' + #size")
public Page<Apartment> listApartments(int page, int size) {
return apartmentMapper.selectPage(new Page<>(page, size),
new QueryWrapper<Apartment>().eq("status", 1));
}
5.3 安全加固方案
- JWT增强实现:
java复制public class JwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken,
OAuth2Authentication authentication) {
Map<String, Object> info = new HashMap<>();
info.put("organization", authentication.getName() + "-尚庭公寓");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
return accessToken;
}
}
- SQL注入防护:
java复制// 使用QueryWrapper而非字符串拼接
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq(StringUtils.isNotBlank(username), "username", username)
.ge(age != null, "age", age);
6. 教学项目特有设计解析
6.1 刻意保留的"坏味道"
- 上帝Service示例:
java复制@Service
public class OmniService {
// 违反单一职责原则
public void handleEverything() {
// 包含了用户、房源、合约等各种操作...
}
}
- 循环依赖陷阱:
java复制@Service
@RequiredArgsConstructor
public class ServiceA {
private final ServiceB serviceB;
}
@Service
@RequiredArgsConstructor
public class ServiceB {
private final ServiceA serviceA; // 启动时会报BeanCurrentlyInCreationException
}
6.2 代码审查要点
审查清单示例:
- 检查Controller是否超过200行
- Service方法是否有超过3层的嵌套if
- 是否存在魔法数字(应定义为常量)
- 日志输出是否规范(使用占位符而非字符串拼接)
- 异常处理是否吞没了原始异常
6.3 重构实践指导
案例:提取租金计算策略
java复制// 重构前
public BigDecimal calculateRent(Apartment apartment, int months) {
BigDecimal base = apartment.getBasePrice();
if(months >= 12) {
return base.multiply(new BigDecimal(months)).multiply(new BigDecimal("0.9"));
} else if(months >= 6) {
// 各种复杂计算...
}
}
// 重构后
public interface RentStrategy {
BigDecimal calculate(BigDecimal basePrice, int months);
}
public class LongTermRentStrategy implements RentStrategy {
@Override
public BigDecimal calculate(BigDecimal basePrice, int months) {
return basePrice.multiply(new BigDecimal(months))
.multiply(new BigDecimal("0.9"));
}
}
7. 企业级项目开发思维培养
7.1 代码质量保障体系
- 静态代码分析配置:
xml复制<!-- pom.xml中配置SpotBugs -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.7.3</version>
</plugin>
- 单元测试覆盖率要求:
java复制@SpringBootTest
public class ApartmentServiceTest {
@Autowired
private ApartmentService service;
@Test
@DisplayName("测试房源创建验证逻辑")
void testCreateValidation() {
Apartment apartment = new Apartment();
assertThrows(IllegalArgumentException.class,
() -> service.createApartment(apartment));
}
}
7.2 持续集成实践
GitLab CI示例配置:
yaml复制stages:
- build
- test
- deploy
build-job:
stage: build
script:
- mvn clean package -DskipTests
test-job:
stage: test
script:
- mvn test
artifacts:
paths:
- target/surefire-reports/
7.3 监控与运维考量
- Spring Boot Actuator配置:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
- 日志收集方案:
xml复制<!-- logback-spring.xml -->
<appender name="ELK" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>127.0.0.1:5000</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
