去年在开发一个民宿管理平台时,我深刻体会到传统人工管理方式的痛点:房东需要手动记录预订信息,租客无法实时查看房源状态,支付流程繁琐...这些问题促使我开发了这套基于Spring Boot的民宿租赁系统。系统采用前后端分离架构,后端使用SpringBoot2框架,前端基于Vue3,数据库选用MySQL8.0,并整合MyBatis-Plus简化数据操作。
这个系统最核心的价值在于:
选择SpringBoot2作为后端框架主要基于以下考虑:
数据库操作层采用MyBatis-Plus而非原生MyBatis,因为:
Vue3相比Vue2的优势在这个项目中体现明显:
Element Plus作为UI框架的选择理由:
MySQL8.0相比5.7版本引入了多项重要改进:
采用JWT+Spring Security实现安全的认证流程:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
关键实现细节:
房源CRUD操作的MyBatis-Plus实现示例:
java复制@Service
public class PropertyServiceImpl extends ServiceImpl<PropertyMapper, Property>
implements PropertyService {
@Override
public Page<PropertyVO> searchProperties(PropertyQuery query, Pageable pageable) {
return baseMapper.selectPropertyPage(
new Page<>(pageable.getPageNumber(), pageable.getPageSize()),
query);
}
@Override
@Transactional
public boolean updatePropertyStatus(Long id, Integer status) {
Property property = getById(id);
if (property == null) {
throw new BusinessException("房源不存在");
}
property.setIsAvailable(status);
return updateById(property);
}
}
订单创建的核心逻辑:
java复制@Transactional
public OrderDTO createOrder(OrderCreateDTO dto) {
// 1. 验证房源可用性
Property property = propertyService.getAvailableProperty(
dto.getPropertyId(),
dto.getCheckInDate(),
dto.getCheckOutDate());
// 2. 计算订单金额
long nights = ChronoUnit.DAYS.between(
dto.getCheckInDate(),
dto.getCheckOutDate());
BigDecimal total = property.getPricePerNight()
.multiply(BigDecimal.valueOf(nights));
// 3. 创建订单记录
Order order = new Order();
BeanUtils.copyProperties(dto, order);
order.setTotalAmount(total);
order.setPaymentStatus(0);
orderMapper.insert(order);
// 4. 发送预订通知
notificationService.sendBookingConfirmation(
order.getUserId(),
property.getOwnerId(),
order.getOrderId());
return convertToDTO(order);
}
采用多级缓存架构提升系统响应速度:
java复制@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return cacheManager;
}
java复制@Cacheable(value = "properties", key = "#id")
public Property getPropertyById(Long id) {
return propertyMapper.selectById(id);
}
java复制@Cacheable(value = "property_page", key = "#query.toString() + #pageable")
public Page<PropertyVO> searchProperties(PropertyQuery query, Pageable pageable) {
// 查询逻辑
}
sql复制ALTER TABLE property_listing
ADD INDEX idx_location_price (location(50), price_per_night);
ALTER TABLE booking_order
ADD INDEX idx_user_property (user_id, property_id);
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
java复制@PreAuthorize("hasRole('LANDLORD') && #property.ownerId == authentication.principal.id")
@PutMapping("/properties/{id}")
public ResponseEntity<?> updateProperty(
@PathVariable Long id,
@RequestBody PropertyUpdateDTO dto) {
// 实现逻辑
}
java复制@ColumnTransformer(
read = "AES_DECRYPT(UNHEX(credit_card), 'encryption-key')",
write = "HEX(AES_ENCRYPT(?, 'encryption-key'))")
@Column(name = "credit_card")
private String creditCard;
java复制@Bean
public FilterRegistrationBean<XssFilter> xssFilter() {
FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
return registration;
}
Docker Compose部署配置示例:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: bnb
MYSQL_USER: appuser
MYSQL_PASSWORD: userpass
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
- redis_data:/data
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/bnb
SPRING_REDIS_HOST: redis
volumes:
mysql_data:
redis_data:
java复制@Timed(value = "property.search", description = "房源搜索耗时")
@GetMapping("/properties")
public Page<PropertyVO> searchProperties(PropertyQuery query, Pageable pageable) {
return propertyService.searchProperties(query, pageable);
}
json复制{
"code": 200,
"message": "success",
"data": {}
}
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600);
}
}
sql复制SELECT * FROM property
WHERE id > (SELECT id FROM property ORDER BY id LIMIT 10000, 1)
LIMIT 20;
这套系统在实际运营中经受住了日均10万PV的考验,核心接口响应时间保持在200ms以内。最大的收获是认识到良好的架构设计对系统可维护性的重要性,特别是在需求频繁变更的互联网环境中。