1. 项目概述与技术栈解析
这套民宿租赁系统采用当前主流的前后端分离架构,后端基于Spring Boot 2框架构建,前端使用Vue 3组合式API开发,数据持久层采用MyBatis-Plus增强工具,数据库选用MySQL 8.0版本。整套系统源码附带完整开发文档,实现了民宿行业的全流程数字化管理,包含房源展示、在线预订、订单管理、支付对接等核心业务模块。
技术栈的版本选择体现了对生产环境稳定性的考量:
- Spring Boot 2.x保持了对Java 8的兼容性,同时提供了完善的自动配置机制
- Vue 3的Composition API使前端组件逻辑组织更灵活
- MyBatis-Plus 3.x版本提供了强大的CRUD增强功能
- MySQL 8.0在JSON支持、窗口函数等方面有显著改进
提示:系统采用Maven多模块设计,将core、web、service等层物理隔离,这种结构在团队协作开发时能有效降低代码耦合度。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境搭建与项目初始化
2.1 基础环境准备
开发环境需要以下组件:
- JDK 1.8+(推荐Amazon Corretto 11)
- Node.js 16.x(Vue 3的稳定支持版本)
- MySQL 8.0.23+(注意开启大小写敏感配置)
- Redis 6.x(用于会话管理和缓存)
配置Maven镜像时建议使用阿里云仓库:
xml复制<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
2.2 数据库初始化
执行项目中的SQL脚本时需注意:
- 先创建数据库并设置字符集:
sql复制CREATE DATABASE homestay DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 导入表结构前建议关闭外键检查:
sql复制SET FOREIGN_KEY_CHECKS = 0;
-- 执行SQL文件
SET FOREIGN_KEY_CHECKS = 1;
3. 核心模块设计与实现
3.1 房源管理模块
采用领域驱动设计(DDD)实现:
java复制// 房源聚合根示例
public class House {
private Long id;
private String title;
private HouseType type; // 枚举值
private List<HouseImage> images; // 值对象集合
private HouseLocation location; // 嵌入对象
// 业务方法
public boolean isAvailable(LocalDate checkIn, LocalDate checkOut) {
// 可用性校验逻辑
}
}
前端使用Vue 3的setup语法:
javascript复制const houseList = ref([])
const loading = ref(false)
const fetchHouses = async (params) => {
loading.value = true
try {
const res = await api.getHouses(params)
houseList.value = res.data.map(item => ({
...item,
cover: item.images?.[0]?.url || defaultImage
}))
} finally {
loading.value = false
}
}
3.2 订单支付流程
支付状态机设计:
java复制public enum OrderStatus {
PENDING_PAYMENT,
PAID,
CONFIRMED,
CANCELLED,
COMPLETED
}
// 状态转换规则
public class OrderStateMachine extends StateMachine<OrderStatus, OrderEvent> {
protected void configure() {
withExternal()
.source(PENDING_PAYMENT)
.target(PAID)
.event(PAYMENT_RECEIVED)
.action(this::processPayment);
}
}
4. 关键技术实现细节
4.1 MyBatis-Plus高级应用
- 自动填充功能实现:
java复制@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUsername());
}
}
- 多租户SQL解析器配置:
java复制public class TenantSqlParser implements TenantLineHandler {
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public Expression getTenantId() {
return new StringValue(TenantContext.getCurrentTenant());
}
}
4.2 Vue 3组合式API实践
封装可复用的搜索逻辑:
javascript复制export function useSearch(apiFunc, initialParams = {}) {
const params = reactive({ ...initialParams })
const data = ref([])
const total = ref(0)
const search = async () => {
try {
const res = await apiFunc(params)
data.value = res.data.list
total.value = res.data.total
} catch (e) {
console.error('Search failed:', e)
}
}
// 自动执行初始搜索
onMounted(search)
return { params, data, total, search }
}
5. 系统部署与优化
5.1 生产环境配置
Nginx前端部署配置要点:
nginx复制location / {
try_files $uri $uri/ /index.html;
gzip on;
gzip_types text/plain application/xml application/javascript;
# 静态资源缓存
location ~* \.(js|css|png|jpg)$ {
expires 365d;
add_header Cache-Control "public";
}
}
5.2 性能优化方案
- 二级缓存配置:
yaml复制spring:
cache:
type: redis
redis:
time-to-live: 3600000 # 1小时
key-prefix: "homestay:"
cache-null-values: false
- 慢SQL监控配置:
java复制@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setMaxTime(1000); // SQL执行最大时长(ms)
interceptor.setFormat(true); // 格式化SQL
return interceptor;
}
6. 常见问题排查指南
6.1 跨域问题解决方案
Spring Boot后端配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
Vue开发环境代理配置:
javascript复制devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
6.2 日期时间处理
统一时区处理方案:
java复制@Configuration
public class DateTimeConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> {
builder.timeZone(TimeZone.getTimeZone("Asia/Shanghai"));
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
};
}
}
前端日期显示处理:
javascript复制import { format } from 'date-fns'
const formatDateTime = (dateStr) => {
return format(new Date(dateStr), 'yyyy-MM-dd HH:mm')
}
7. 扩展功能实现思路
7.1 智能推荐算法集成
基于用户行为的协同过滤:
java复制public List<House> recommendHouses(Long userId) {
// 1. 获取用户历史行为数据
List<UserBehavior> behaviors = behaviorMapper.selectByUser(userId);
// 2. 计算相似用户
Map<Long, Double> similarUsers = cfService.findSimilarUsers(userId);
// 3. 生成推荐结果
return houseRepository.findRecommended(similarUsers.keySet());
}
7.2 微信小程序对接
获取OpenID的示例:
java复制@RestController
@RequestMapping("/wx")
public class WxAuthController {
@GetMapping("/auth")
public ResponseEntity<String> auth(@RequestParam String code) {
String url = String.format(
"https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
appId, appSecret, code);
// 使用RestTemplate调用微信接口
WxAuthResponse response = restTemplate.getForObject(url, WxAuthResponse.class);
return ResponseEntity.ok(response.getOpenid());
}
}
8. 安全防护措施
8.1 SQL注入防护
MyBatis-Plus的Wrapper使用规范:
java复制// 错误示范(存在注入风险)
QueryWrapper<User> wrapper = new QueryWrapper<>()
.apply("username = '" + username + "'");
// 正确做法
QueryWrapper<User> safeWrapper = new QueryWrapper<>()
.eq("username", username)
.likeRight("phone", "138");
8.2 XSS防护方案
前端使用DOMPurify过滤:
javascript复制import DOMPurify from 'dompurify'
const clean = DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong'],
ALLOWED_ATTR: ['class']
})
后端统一处理:
java复制@ControllerAdvice
public class XssProtectionAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof String) {
return HtmlUtils.htmlEscape((String) body);
}
return body;
}
}
9. 项目文档使用指南
9.1 API文档生成
Swagger集成配置:
java复制@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.homestay.controller"))
.paths(PathSelectors.any())
.build()
.apiInfo(metaData());
}
private ApiInfo metaData() {
return new ApiInfoBuilder()
.title("Homestay API Documentation")
.description("民宿系统接口文档")
.version("1.0.0")
.build();
}
}
9.2 数据库文档生成
使用SchemaSpy生成ER图:
bash复制java -jar schemaspy-6.1.0.jar \
-t mysql \
-db homestay \
-host localhost \
-u root \
-p password \
-o ./docs/db
10. 二次开发建议
- 扩展字段建议通过JSON类型存储:
sql复制ALTER TABLE house ADD COLUMN extend_info JSON COMMENT '扩展信息';
- 使用Spring事件机制解耦业务:
java复制// 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
public OrderCreatedEvent(Order source) {
super(source);
}
}
// 发布事件
applicationContext.publishEvent(new OrderCreatedEvent(order));
// 监听处理
@Component
public class OrderEventHandler {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送通知等后续处理
}
}
- 前端组件按需加载:
javascript复制const HouseCard = defineAsyncComponent(() =>
import('./components/HouseCard.vue')
)
