这个基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0的旅游网站系统,是一个典型的前后端分离架构的现代化Web应用。作为旅游行业的数字化解决方案,它涵盖了用户管理、产品展示、订单处理等核心业务模块,同时采用了当前主流的技术组合方案。
技术栈选择体现了几个关键考量:
提示:这套技术组合特别适合中小型旅游企业的数字化需求,既能满足当前业务规模,又为未来扩展预留了空间。
系统采用典型的前后端分离设计:
code复制前端(Vue3) ← HTTP/HTTPS → 后端(SpringBoot) ← JDBC → MySQL
这种架构的优势在于:
系统主要包含以下功能模块:
标准的Maven项目结构:
code复制src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── config/ # 配置类
│ │ ├── controller/ # 控制器
│ │ ├── entity/ # 实体类
│ │ ├── mapper/ # MyBatis接口
│ │ ├── service/ # 业务逻辑
│ │ └── Application.java
│ └── resources/
│ ├── application.yml # 主配置文件
│ └── mapper/ # XML映射文件
在SpringBoot中集成MyBatis-Plus的步骤:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/travel_db?useSSL=false
username: root
password: yourpassword
driver-class-name: com.mysql.cj.jdbc.Driver
java复制@Mapper
public interface ProductMapper extends BaseMapper<Product> {
// 自定义查询方法
@Select("SELECT * FROM product WHERE price BETWEEN #{min} AND #{max}")
List<Product> selectByPriceRange(@Param("min") BigDecimal min,
@Param("max") BigDecimal max);
}
使用Vite创建Vue3项目:
bash复制npm create vite@latest travel-web --template vue
cd travel-web
npm install
关键依赖:
典型页面结构:
vue复制<template>
<div class="product-list">
<ProductFilter @filter="handleFilter" />
<ProductItem
v-for="product in filteredProducts"
:key="product.id"
:product="product"
@add-to-cart="handleAddToCart"
/>
<Pagination
:total="total"
:current="currentPage"
@page-change="handlePageChange"
/>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useProductStore } from '@/stores/product'
const productStore = useProductStore()
const filterConditions = ref({})
const filteredProducts = computed(() => {
return productStore.getFilteredProducts(filterConditions.value)
})
function handleFilter(conditions) {
filterConditions.value = conditions
}
</script>
核心表结构示例:
sql复制CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`description` text,
`price` decimal(10,2) NOT NULL,
`stock` int NOT NULL DEFAULT '0',
`cover_image` varchar(255),
`detail_images` json DEFAULT NULL,
`tags` json DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
FULLTEXT KEY `idx_name_desc` (`name`,`description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
索引优化:
查询优化:
缓存策略:
认证与授权:
输入验证:
API安全:
使用Docker Compose快速搭建环境:
yaml复制version: '3.8'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: travel_db
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- db
frontend:
build: ./frontend
ports:
- "3000:3000"
volumes:
mysql_data:
后端部署:
前端部署:
数据库:
SpringBoot后端配置CORS:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
后端处理文件上传:
java复制@PostMapping("/upload")
public Result<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Result.fail("请选择文件");
}
try {
String fileName = UUID.randomUUID() +
file.getOriginalFilename().substring(
file.getOriginalFilename().lastIndexOf(".")
);
Path path = Paths.get(uploadDir, fileName);
Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
return Result.success("/uploads/" + fileName);
} catch (IOException e) {
log.error("文件上传失败", e);
return Result.fail("上传失败");
}
}
前端Vue3实现:
vue复制<template>
<div>
<input type="file" @change="handleFileChange" />
<button @click="upload">上传</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const file = ref(null)
function handleFileChange(e) {
file.value = e.target.files[0]
}
async function upload() {
if (!file.value) return
const formData = new FormData()
formData.append('file', file.value)
try {
const res = await axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
console.log('上传成功:', res.data)
} catch (err) {
console.error('上传失败:', err)
}
}
</script>
前端性能优化:
后端性能优化:
数据库优化:
完整的项目文档应包含:
提示:使用Swagger自动生成API文档,保持文档与代码同步:
java复制@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller"))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("旅游网站API文档")
.description("前后端接口定义")
.version("1.0")
.build();
}
}
移动端适配:
功能扩展:
技术升级:
运维增强:
这套旅游网站系统源码采用了当前主流的技术栈,既适合作为学习项目了解完整的企业级应用开发流程,也具备实际商业应用的潜力。在实际开发中,建议根据具体业务需求进行定制化调整,特别注意性能优化和安全防护方面的工作。