从零到一:使用Cursor构建Java+Vue前后端分离项目的完整指南
个人名片
🎓作者简介:java领域优质创作者
🌐个人主页:码农阿豪
📞工作室:新空间代码工作室(提供各种软件服务)
💌个人邮箱:[2435024119@qq.com]
📱个人微信:15279484656
🌐个人导航网站:www.forff.top
💡座右铭:总有人要赢。为什么不能是我呢?
- 专栏导航:
码农阿豪系列专栏导航
面试专栏:收集了java相关高频面试题,面试实战总结🍻🎉🖥️
Spring5系列专栏:整理了Spring5重要知识点与实战演练,有案例可直接使用🚀🔧💻
Redis专栏:Redis从零到一学习分享,经验总结,案例实战💐📝💡
全栈系列专栏:海纳百川有容乃大,可能你想要的东西里面都有🤸🌱🚀
目录
从零到一:使用Cursor构建Java+Vue前后端分离项目的完整指南
引言
在现代Web开发中,前后端分离架构已成为行业标准。这种架构模式不仅提高了开发效率,还让团队协作更加顺畅。今天,我们将探讨如何利用Cursor这个强大的AI编程助手,从零开始构建一个完整的Java后端和Vue前端分离项目。无论你是刚入门的开发者还是经验丰富的工程师,这篇文章都将为你提供一个清晰的路线图。
一、项目架构设计
1.1 为什么选择前后端分离架构?
前后端分离架构的核心思想是将用户界面(前端)与业务逻辑和数据存储(后端)完全解耦。这种架构的优势在于:
- 并行开发:前后端团队可以同时工作,提高开发效率
- 技术栈灵活性:前后端可以独立选择最适合的技术栈
- 更好的可维护性:清晰的分离让代码更易于理解和维护
- 可扩展性:可以轻松添加移动端应用或其他客户端
- 性能优化:前端可以独立部署和优化用户体验
1.2 技术栈选择
后端技术栈:
- Java 11+:稳定可靠的企业级编程语言
- Spring Boot 2.7+:快速构建生产级应用的框架
- Spring Security:安全认证和授权
- JPA/Hibernate:对象关系映射
- MySQL 8.0:关系型数据库
- Maven:项目构建和依赖管理
前端技术栈:
- Vue 3.0+:渐进式JavaScript框架
- TypeScript:提供类型安全的JavaScript超集
- Element Plus:UI组件库
- Axios:HTTP客户端
- Vue Router:路由管理
- Pinia:状态管理
- Vite:构建工具,提供极速的开发体验
二、给Cursor的完整提示工程
2.1 理解Cursor的能力
Cursor是基于GPT-4的AI编程助手,它能够:
- 生成完整的代码文件
- 解释复杂的技术概念
- 调试和修复代码错误
- 提供最佳实践建议
- 协助架构设计决策
2.2 构建完整提示的要素
一个优秀的提示应该包含以下要素:
- 明确的目标:清楚说明你要构建什么
- 技术栈要求:指定使用的技术和版本
- 架构规范:定义项目结构和设计模式
- 功能需求:详细描述项目功能
- 代码风格:指定编码规范和约定
- 特殊要求:任何特定的业务或技术需求
2.3 完整提示示例
以下是我为Cursor设计的完整提示模板:
我正在创建一个Java + Vue的前后端分离项目,需要你帮助我从零开始构建完整的代码结构。
## 项目概述
开发一个任务管理系统,包含用户认证、任务创建、分配、跟踪和报告功能。
## 后端要求 (Java/Spring Boot)
1. 使用Spring Boot 2.7.5和Java 11
2. 采用三层架构:Controller → Service → Repository
3. 实现RESTful API设计
4. 使用JWT进行安全认证
5. 集成Spring Security
6. 使用MySQL数据库,配置连接池
7. 实现全局异常处理
8. 添加请求参数验证
9. 配置CORS支持前端访问
10. 集成Swagger/OpenAPI文档
## 数据库设计
需要以下核心表:
1. users: 用户表 (id, username, email, password, roles, created_at)
2. tasks: 任务表 (id, title, description, status, priority, assignee_id, creator_id, due_date, created_at)
3. comments: 评论表 (id, task_id, user_id, content, created_at)
## 前端要求 (Vue 3 + TypeScript)
1. 使用Vue 3.2+和TypeScript 4.9+
2. 采用Composition API风格
3. 使用Element Plus组件库
4. 实现路由守卫进行权限控制
5. 封装axios请求拦截器
6. 使用Pinia进行状态管理
7. 实现响应式布局
8. 添加表单验证
9. 配置环境变量
10. 遵循ESLint + Prettier代码规范
## 功能模块
1. 用户认证模块(登录、注册、退出)
2. 任务管理模块(增删改查、筛选、排序)
3. 用户管理模块(仅管理员可见)
4. 仪表板(统计图表)
5. 个人中心(个人信息、修改密码)
## 部署要求
1. 后端打包为Docker镜像
2. 前端部署到Nginx
3. 提供docker-compose配置
4. 配置生产环境和开发环境
## 其他要求
1. 代码注释率不低于20%
2. 使用中文注释
3. 遵循阿里巴巴Java开发手册
4. 前端组件和函数使用英文命名
5. 所有API返回统一JSON格式
请从项目结构设计开始,逐步生成所有必要的配置文件、实体类、接口和组件。
三、后端实现详解
3.1 项目结构设计
backend/
├── src/main/java/com/taskmanager/
│ ├── TaskManagerApplication.java
│ ├── config/ # 配置类
│ ├── controller/ # 控制器层
│ ├── service/ # 业务逻辑层
│ ├── repository/ # 数据访问层
│ ├── model/ # 实体类
│ ├── dto/ # 数据传输对象
│ ├── security/ # 安全相关
│ └── exception/ # 异常处理
├── src/main/resources/
│ ├── application.yml
│ ├── application-dev.yml
│ └── application-prod.yml
└── pom.xml
3.2 Spring Boot应用主类
package com.taskmanager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class TaskManagerApplication {
public static void main(String[] args) {
SpringApplication.run(TaskManagerApplication.class, args);
}
}
3.3 统一响应格式
package com.taskmanager.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiResponse<T> implements Serializable {
private Integer code;
private String message;
private T data;
private Long timestamp;
public ApiResponse() {
this.timestamp = System.currentTimeMillis();
}
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(200);
response.setMessage("操作成功");
response.setData(data);
return response;
}
public static <T> ApiResponse<T> error(Integer code, String message) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(code);
response.setMessage(message);
return response;
}
}
3.4 用户实体类
package com.taskmanager.model;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "users")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
private String password;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "role")
private Set<String> roles = new HashSet<>();
@Column(name = "created_at")
private LocalDateTime createdAt = LocalDateTime.now();
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
}
3.5 JWT认证配置
package com.taskmanager.security;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtTokenUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
// 其他工具方法...
}
四、前端实现详解
4.1 Vue项目结构
frontend/
├── src/
│ ├── api/ # API接口
│ ├── assets/ # 静态资源
│ ├── components/ # 组件
│ ├── composables/ # 组合式函数
│ ├── layout/ # 布局组件
│ ├── router/ # 路由配置
│ ├── stores/ # Pinia状态管理
│ ├── types/ # TypeScript类型定义
│ ├── utils/ # 工具函数
│ ├── views/ # 页面组件
│ ├── App.vue
│ └── main.ts
├── public/
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
├── vite.config.ts # Vite配置
└── package.json
4.2 环境配置
// .env.development
VITE_APP_TITLE = '任务管理系统 - 开发环境'
VITE_APP_BASE_API = 'http://localhost:8080/api'
VITE_APP_UPLOAD_URL = 'http://localhost:8080/api/upload'
// .env.production
VITE_APP_TITLE = '任务管理系统'
VITE_APP_BASE_API = '/api'
VITE_APP_UPLOAD_URL = '/api/upload'
4.3 Axios实例封装
// src/utils/request.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/stores/user'
const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 10000,
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
// 请求拦截器
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
const userStore = useUserStore()
if (userStore.token && config.headers) {
config.headers['Authorization'] = `Bearer ${userStore.token}`
}
return config
},
(error: any) => {
Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
const res = response.data
if (res.code !== 200) {
ElMessage.error(res.message || '请求失败')
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res.data
}
},
(error: any) => {
if (error.response?.status === 401) {
// 处理未授权
const userStore = useUserStore()
userStore.logout()
window.location.href = '/login'
}
ElMessage.error(error.message || '请求失败')
return Promise.reject(error)
}
)
export default service
4.4 用户状态管理
// src/stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { login, logout, getUserInfo } from '@/api/user'
import type { LoginForm, UserInfo } from '@/types/user'
export const useUserStore = defineStore('user', () => {
const token = ref(localStorage.getItem('token') || '')
const userInfo = ref<UserInfo | null>(null)
const roles = ref<string[]>([])
const isLoggedIn = computed(() => !!token.value)
const isAdmin = computed(() => roles.value.includes('ROLE_ADMIN'))
const loginAction = async (loginForm: LoginForm) => {
try {
const data = await login(loginForm)
token.value = data.token
localStorage.setItem('token', data.token)
await getUserInfoAction()
return data
} catch (error) {
return Promise.reject(error)
}
}
const getUserInfoAction = async () => {
try {
const data = await getUserInfo()
userInfo.value = data.user
roles.value = data.roles
return data
} catch (error) {
return Promise.reject(error)
}
}
const logoutAction = async () => {
try {
await logout()
} finally {
resetState()
}
}
const resetState = () => {
token.value = ''
userInfo.value = null
roles.value = []
localStorage.removeItem('token')
}
return {
token,
userInfo,
roles,
isLoggedIn,
isAdmin,
loginAction,
getUserInfoAction,
logoutAction
}
})
五、数据库设计与优化
5.1 数据库表结构
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_username (username),
INDEX idx_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 用户角色关联表
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
role VARCHAR(50) NOT NULL,
PRIMARY KEY (user_id, role),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 任务表
CREATE TABLE tasks (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
description TEXT,
status ENUM('PENDING', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED') DEFAULT 'PENDING',
priority ENUM('LOW', 'MEDIUM', 'HIGH', 'URGENT') DEFAULT 'MEDIUM',
assignee_id BIGINT,
creator_id BIGINT NOT NULL,
due_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (assignee_id) REFERENCES users(id) ON DELETE SET NULL,
FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_status (status),
INDEX idx_priority (priority),
INDEX idx_assignee (assignee_id),
INDEX idx_creator (creator_id),
INDEX idx_due_date (due_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 评论表
CREATE TABLE comments (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
task_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_task (task_id),
INDEX idx_user (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
5.2 数据库优化策略
-
索引优化:
- 为经常查询的字段创建索引
- 使用复合索引优化联合查询
- 定期分析查询性能,删除不必要的索引
-
查询优化:
- 避免SELECT *,只选择需要的字段
- 使用分页查询大数据集
- 合理使用JOIN,避免笛卡尔积
-
连接池配置:
spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000
六、部署与运维
6.1 Docker容器化部署
# 后端Dockerfile
FROM openjdk:11-jre-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 前端Dockerfile
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
6.2 Docker Compose配置
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: task-manager-mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: taskmanager
MYSQL_USER: taskuser
MYSQL_PASSWORD: taskpass
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- task-network
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: task-manager-backend
environment:
SPRING_PROFILES_ACTIVE: prod
DB_HOST: mysql
DB_PORT: 3306
DB_NAME: taskmanager
DB_USERNAME: taskuser
DB_PASSWORD: taskpass
ports:
- "8080:8080"
depends_on:
- mysql
networks:
- task-network
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: task-manager-frontend
ports:
- "80:80"
depends_on:
- backend
networks:
- task-network
networks:
task-network:
driver: bridge
volumes:
mysql-data:
七、开发流程优化
7.1 Git分支策略
main
├── develop
│ ├── feature/user-auth
│ ├── feature/task-management
│ └── bugfix/login-issue
├── release/v1.0.0
└── hotfix/v1.0.1
7.2 CI/CD流水线
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Backend
run: |
cd backend
mvn clean package -DskipTests
- name: Build Frontend
run: |
cd frontend
npm install
npm run build
- name: Deploy to Server
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /var/www/task-manager
git pull origin main
docker-compose down
docker-compose up -d --build
八、使用Cursor的最佳实践
8.1 迭代式开发
不要期望Cursor一次性生成完美的代码。采用迭代方式:
- 先生成基础框架
- 添加核心功能
- 逐步完善细节
- 不断优化和重构
8.2 精准提问技巧
- 具体化需求:不要问"如何实现登录",要问"如何使用Spring Security实现JWT认证"
- 提供上下文:给出相关代码片段或错误信息
- 分步骤请求:先要架构设计,再要具体实现
- 验证和测试:生成的代码一定要手动测试
8.3 代码审查与优化
即使是AI生成的代码也需要人工审查:
- 检查安全性问题
- 验证业务逻辑正确性
- 优化性能瓶颈
- 确保代码符合规范
九、项目扩展与优化
9.1 后续功能扩展
- 即时通讯:集成WebSocket实现实时通知
- 文件管理:支持任务附件上传和预览
- 数据导出:导出任务数据为Excel或PDF
- 移动端适配:使用响应式设计或开发移动端应用
- 第三方集成:集成日历、邮件通知等服务
9.2 性能优化策略
-
前端优化:
- 代码分割和懒加载
- 图片压缩和CDN加速
- 服务端渲染(SSR)考虑
-
后端优化:
- 数据库查询缓存
- API响应压缩
- 异步处理耗时操作
-
监控和日志:
- 集成Prometheus和Grafana
- 统一日志收集
- 错误追踪和报警
结语
通过本文的详细指南,你已经掌握了使用Cursor从零开始构建Java+Vue前后端分离项目的完整流程。从项目架构设计到具体实现,从本地开发到生产部署,每一个环节都有详细的说明和示例代码。
记住,AI助手如Cursor是强大的工具,但它不能替代开发者的思考和决策。最成功的项目往往是人类智慧与AI能力完美结合的产物。随着你对Cursor等工具的熟练使用,你会发现开发效率大幅提升,同时也能保证代码质量。
现在,你已经具备了构建企业级应用的所有知识。开始你的项目吧,在实践中不断学习和完善。开发之旅充满挑战,但也充满乐趣和成就感。祝你在编码的世界里探索出更多精彩!


浙公网安备 33010602011771号