SpringBoot 3.x + Vue 3 + MyBatis-Plus:从零搭建一个任务管理Demo(附跨域和Swagger配置)

发布时间:2026/5/28 13:38:38

SpringBoot 3.x + Vue 3 + MyBatis-Plus:从零搭建一个任务管理Demo(附跨域和Swagger配置) SpringBoot 3.x Vue 3 MyBatis-Plus构建现代化任务管理系统的全栈实践在当今快速迭代的技术环境中全栈开发能力已成为中高级开发者的标配技能。本文将带您深入探索如何基于SpringBoot 3.x、Vue 3和MyBatis-Plus这一黄金技术组合从零构建一个具备生产级特性的任务管理系统。不同于基础教程我们将重点关注技术栈的最新特性、工程化实践和性能优化技巧帮助您在实战中掌握现代化全栈开发的核心要领。1. 技术选型与环境准备1.1 技术栈优势分析SpringBoot 3.x作为当前Java生态的标杆框架带来了多项突破性改进原生支持GraalVM Native Image显著提升启动速度和内存效率全面拥抱JDK 17特性如Record类、模式匹配等现代语法增强的Micrometer指标监控为云原生部署提供更好支持Vue 3的Composition API彻底改变了前端开发模式更灵活的逻辑复用能力告别Options API的碎片化问题基于Proxy的响应式系统性能提升40%以上更小的打包体积约10KB gzippedMyBatis-Plus3.5版本新增特性值得关注动态表名支持轻松应对分表场景增强的Lambda表达式查询编译期安全检查全新的SQL注入器机制扩展性更强1.2 开发环境配置推荐使用以下环境组合# JDK版本验证 java -version # 要求17 mvn -v # 3.8.1 node -v # 16.14 npm -v # 8.3IDE配置建议IntelliJ IDEA 2022.3安装Vue.js插件VS Code配合Volar扩展Vue 3官方推荐Lombok插件必须安装以避免编译错误关键依赖版本锁定pom.xmlproperties spring-boot.version3.1.0/spring-boot.version mybatis-plus.version3.5.3.1/mybatis-plus.version /properties2. 后端工程架构设计2.1 项目初始化与基础配置使用Spring Initializr创建项目时注意勾选Spring WebReactive可选MyBatis FrameworkLombokSpringDoc OpenAPI替代传统Swagger数据库配置示例application.ymlspring: datasource: url: jdbc:mysql://localhost:3306/task_management?useSSLfalse username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 20 connection-timeout: 30000 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted # 逻辑删除字段 logic-delete-value: 1 logic-not-delete-value: 02.2 领域模型与持久层设计采用DDD分层架构定义核心领域模型Data TableName(tm_task) Schema(description 任务实体) public class Task { TableId(type IdType.AUTO) private Long id; Schema(description 任务内容) private String content; Schema(description 任务状态) private TaskStatus status; TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; } public enum TaskStatus { PENDING, PROCESSING, COMPLETED, ARCHIVED }Mapper接口增强实践public interface TaskMapper extends BaseMapperTask { Select(SELECT * FROM tm_task WHERE status #{status}) ListTask selectByStatus(Param(status) TaskStatus status); Update(UPDATE tm_task SET content#{content} WHERE id#{id}) int updateContentById(Param(id) Long id, Param(content) String content); }提示MyBatis-Plus的Wrapper条件构造器能处理90%的查询场景复杂SQL建议使用Select注解明确编写3. 业务逻辑与API实现3.1 服务层设计模式采用CQRS模式分离读写操作public interface TaskQueryService { PageTaskVO queryTasks(TaskQuery query, Pageable pageable); TaskDetailVO getTaskDetail(Long id); } public interface TaskCommandService { Long createTask(TaskCreateCommand command); void updateTask(TaskUpdateCommand command); void deleteTask(Long id); }事务处理最佳实践Service RequiredArgsConstructor public class TaskCommandServiceImpl implements TaskCommandService { private final TaskMapper taskMapper; private final TaskHistoryService historyService; Transactional(rollbackFor Exception.class) Override public void updateTask(TaskUpdateCommand command) { Task task taskMapper.selectById(command.getId()); if (task null) { throw new BusinessException(任务不存在); } Task beforeUpdate BeanUtil.copyProperties(task, Task.class); BeanUtil.copyProperties(command, task); taskMapper.updateById(task); historyService.recordUpdate(beforeUpdate, task); } }3.2 控制层RESTful设计响应式编程实践可选RestController RequestMapping(/api/tasks) Tag(name 任务管理API) public class TaskController { private final TaskQueryService queryService; private final TaskCommandService commandService; Operation(summary 分页查询任务) GetMapping public ResponseEntityPageResultTaskVO listTasks( ParameterObject TaskQuery query, ParameterObject Pageable pageable) { return ResponseEntity.ok(queryService.queryTasks(query, pageable)); } Operation(summary 创建任务) PostMapping public ResponseEntityLong createTask( Valid RequestBody TaskCreateCommand command) { return ResponseEntity.created(URI.create(/api/tasks)) .body(commandService.createTask(command)); } }全局异常处理增强RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(BusinessException.class) public ResponseEntityErrorResult handleBusinessException(BusinessException ex) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(new ErrorResult(ex.getCode(), ex.getMessage())); } ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntityErrorResult handleValidationException( MethodArgumentNotValidException ex) { String message ex.getBindingResult().getAllErrors().stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.joining(; )); return ResponseEntity.badRequest() .body(new ErrorResult(VALIDATION_FAILED, message)); } }4. 前端工程化实践4.1 Vue 3项目初始化使用Vite创建项目比Webpack快10倍npm create vitelatest task-manager-frontend --template vue-ts cd task-manager-frontend npm install axios pinia element-plus --save推荐的项目结构src/ ├── api/ # API请求封装 ├── assets/ # 静态资源 ├── components/ # 通用组件 ├── composables/ # 组合式函数 ├── router/ # 路由配置 ├── stores/ # Pinia状态管理 ├── types/ # TypeScript类型定义 ├── views/ # 页面组件 ├── App.vue └── main.ts4.2 状态管理与API交互Pinia状态管理示例// stores/task.ts import { defineStore } from pinia import type { TaskVO } from /types interface TaskState { tasks: TaskVO[] loading: boolean error: string | null } export const useTaskStore defineStore(task, { state: (): TaskState ({ tasks: [], loading: false, error: null }), actions: { async fetchTasks() { this.loading true try { const { data } await api.get(/api/tasks) this.tasks data } catch (err) { this.error err.message } finally { this.loading false } } } })API服务封装技巧// api/index.ts import axios from axios const api axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10000, headers: { Content-Type: application/json } }) // 请求拦截器 api.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) // 响应拦截器 api.interceptors.response.use( response { if (response.data?.code ! 200) { return Promise.reject(response.data) } return response.data }, error { if (error.response?.status 401) { // 处理未授权 } return Promise.reject(error) } ) export default api4.3 任务列表页面实现组合式API实践script setup langts import { ref, onMounted } from vue import { useTaskStore } from /stores/task import type { TaskVO } from /types const taskStore useTaskStore() const pagination ref({ page: 1, pageSize: 10, total: 0 }) onMounted(() { loadTasks() }) const loadTasks async () { await taskStore.fetchTasks({ page: pagination.value.page, size: pagination.value.pageSize }) pagination.value.total taskStore.total } /script template el-table :datataskStore.tasks v-loadingtaskStore.loading el-table-column propid labelID width80 / el-table-column propcontent label内容 / el-table-column propstatus label状态 width120 template #default{ row } el-tag :typestatusTagType(row.status) {{ statusText(row.status) }} /el-tag /template /el-table-column /el-table el-pagination v-model:current-pagepagination.page :page-sizepagination.pageSize :totalpagination.total current-changeloadTasks / /template5. 前后端协同开发关键点5.1 跨域解决方案进阶SpringBoot 3.x跨域配置优化Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(http://localhost:5173) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .exposedHeaders(Authorization) .allowCredentials(true) .maxAge(3600); } }生产环境建议使用Nginx反向代理解决跨域配置CORS白名单而非全开放启用HTTPS确保传输安全5.2 API文档集成SpringDoc OpenAPI配置示例Configuration OpenAPIDefinition( info Info( title 任务管理系统API, version 1.0, description 基于SpringBoot3和Vue3的全栈实现 ) ) public class OpenApiConfig { Bean public OpenAPI customizeOpenAPI() { return new OpenAPI() .addSecurityItem(new SecurityRequirement().addList(JWT)) .components(new Components() .addSecuritySchemes(JWT, new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme(bearer) .bearerFormat(JWT))); } }访问地址OpenAPI JSON: http://localhost:8080/v3/api-docsSwagger UI: http://localhost:8080/swagger-ui.html5.3 联调调试技巧前端代理配置vite.config.tsexport default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } })常用调试工具Chrome开发者工具Network面板Postman/Insomnia接口测试MyBatis-Plus性能分析插件dependency groupIdp6spy/groupId artifactIdp6spy/artifactId version3.9.1/version /dependency6. 部署与性能优化6.1 后端打包优化分层打包配置pom.xmlplugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration layers enabledtrue/enabled /layers /configuration /plugin构建Docker镜像最佳实践# 第一阶段构建 FROM maven:3.8.6-eclipse-temurin-17 as builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 第二阶段运行 FROM eclipse-temurin:17-jre-jammy WORKDIR /app COPY --frombuilder /app/target/*.jar app.jar ENTRYPOINT [java, -jar, app.jar]6.2 前端部署策略Vite生产构建命令npm run buildNginx配置示例server { listen 80; server_name yourdomain.com; location / { root /var/www/task-manager; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://backend:8080; proxy_set_header Host $host; } }6.3 性能监控与调优SpringBoot Actuator集成management: endpoints: web: exposure: include: health,metrics,info metrics: tags: application: ${spring.application.name}前端性能监测使用vite-plugin-pwaimport { VitePWA } from vite-plugin-pwa export default defineConfig({ plugins: [ VitePWA({ registerType: autoUpdate, workbox: { clientsClaim: true, skipWaiting: true } }) ] })7. 安全加固方案7.1 认证与授权JWT认证实现Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests(auth - auth .requestMatchers(/api/auth/**).permitAll() .anyRequest().authenticated() ) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } }7.2 数据安全防护SQL注入防护始终使用MyBatis参数绑定避免字符串拼接SQL启用MyBatis-Plus的SQL注入器XSS防护方案Bean public FilterRegistrationBeanXssFilter xssFilter() { FilterRegistrationBeanXssFilter registration new FilterRegistrationBean(); registration.setFilter(new XssFilter()); registration.addUrlPatterns(/*); return registration; }7.3 前端安全实践Vue安全最佳实践使用v-html时进行内容消毒设置CSP策略敏感操作需要二次确认const deleteTask async (id: number) { try { await ElMessageBox.confirm(确定删除该任务吗, 警告, { confirmButtonText: 确定, cancelButtonText: 取消, type: warning }) await api.delete(/api/tasks/${id}) } catch (err) { // 处理取消或错误 } }

相关新闻