AI生成Spring Boot + Vue 3 + MySQL + MyBatis-Plus的项目实战

Role

你是一位拥有10年经验的全栈开发专家,精通 Java Spring Boot 后端架构与 Vue 3 前端生态。你特别擅长使用 **MyBatis-Plus** 进行高效的数据持久层开发。

Project Goal

请为我生成一个基于 **Spring Boot + Vue 3 + MySQL + MyBatis-Plus** 的人员管理系统(Employee Management System)的核心代码框架。

Tech Stack Constraints

  • **后端**: Java 17 (或 1.8), Spring Boot 3.x, **MyBatis-Plus 3.5.x**, MySQL 8.0。

  • **前端**: Vue 3 (Composition API + `<script setup>`), Vite, Axios, Element Plus (UI 组件库)。

  • **工具库**: Lombok, Hutool (可选)。

Functional Requirements

请按照以下模块提供核心代码实现:

  1. **数据库设计 (MySQL)**
  • 提供 `sys_user` (用户表) 和 `sys_employee` (员工信息表) 的 SQL 建表语句。

  • 字段需包含:id (主键自增), username, password, name, email, phone, status, create_time, update_time, is_deleted (逻辑删除字段)。

  1. **后端实现 (Spring Boot + MyBatis-Plus)**
  • **配置**: 提供 `application.yml` 的关键配置(数据库连接、MP 配置如逻辑删除、分页插件)。

  • **实体层**: `User` 和 `Employee` 实体类,使用 MP 的注解(如 `@TableName`, `@TableId`, `@TableLogic`)。

  • **持久层**: 定义 `EmployeeMapper` 接口,继承 **`BaseMapper<Employee>`**。

  • **业务层**: `EmployeeService` 接口继承 **`IService<Employee>`**,实现类继承 **`ServiceImpl<Mapper, Entity>`**。请展示如何使用 **`LambdaQueryWrapper`** 进行条件查询。

  • **控制层**: `AuthController` (登录/注册) 和 `EmployeeController`。

  • **通用封装**: 提供统一的响应结果类 `Result<T>` (包含 code, msg, data) 和分页结果封装。

  1. **前端实现 (Vue 3)**
  • **API 封装**: 使用 Axios 封装请求拦截器(处理 Token)和 API 接口调用函数。

  • **视图层**:

  • **登录/注册页**: 包含表单验证逻辑。

  • **人员管理页**: 使用 Element Plus 的 Table 和 Pagination 组件,实现列表展示(分页)、新增/编辑弹窗、删除(调用后端逻辑删除或物理删除)。

Output Rules

  • 代码需要包含关键注释,特别是 MP 特有的注解解释。

  • 重点展示 MP 如何简化 CRUD 操作(例如不需要写 XML,直接使用 `baseMapper.selectList` 等)。

  • 请按模块分块展示核心代码。

数据库设计(MySQL)

sql 复制代码
-- 用户表(系统账号)
CREATE TABLE `sys_user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `username` varchar(64) NOT NULL COMMENT '登录账号',
  `password` varchar(128) NOT NULL COMMENT '加密密码',
  `name` varchar(32) DEFAULT NULL COMMENT '真实姓名',
  `email` varchar(128) DEFAULT NULL COMMENT '邮箱',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
  `status` tinyint DEFAULT '1' COMMENT '状态(0禁用 1正常)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint DEFAULT '0' COMMENT '逻辑删除(0未删 1已删)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户表';

-- 员工信息表(业务数据)
CREATE TABLE `sys_employee` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` bigint NOT NULL COMMENT '关联用户ID',
  `name` varchar(32) NOT NULL COMMENT '员工姓名',
  `gender` tinyint DEFAULT '0' COMMENT '性别(0未知 1男 2女)',
  `email` varchar(128) DEFAULT NULL COMMENT '工作邮箱',
  `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `department` varchar(64) DEFAULT NULL COMMENT '所属部门',
  `position` varchar(64) DEFAULT NULL COMMENT '职位',
  `status` tinyint DEFAULT '1' COMMENT '在职状态(0离职 1在职)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint DEFAULT '0' COMMENT '逻辑删除(0未删 1已删)',
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='员工信息表';

后端核心实现

配置文件(application.yml)
yaml 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/emp_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-field: isDeleted  # 全局逻辑删除字段
      logic-not-delete-value: 0      # 未删除值
      logic-delete-value: 1          # 已删除值
  type-aliases-package: com.example.ems.model.entity
实体类(使用MyBatis-Plus注解)
java 复制代码
// User.java
@Data
@TableName("sys_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private String password;
    private String name;
    private String email;
    private String phone;
    private Integer status;
    
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
    @TableLogic
    private Integer isDeleted;
}

// Employee.java
@Data
@TableName("sys_employee")
public class Employee {
    @TableId(type = IdType.AUTO)
    private Long id;
    private Long userId;
    private String name;
    private Integer gender;
    private String email;
    private String phone;
    private String department;
    private String position;
    private Integer status;
    
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
    @TableLogic
    private Integer isDeleted;
}
Mapper接口(继承BaseMapper)
java 复制代码
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
    // 所有基础CRUD方法已通过BaseMapper继承
}

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 自定义查询示例
    @Select("SELECT * FROM sys_user WHERE username = #{username} AND is_deleted = 0")
    User selectByUsername(@Param("username") String username);
}
Service层实现
java 复制代码
// 服务接口
public interface EmployeeService extends IService<Employee> {
    Page<Employee> listByCondition(EmployeeQueryDTO dto);
}

// 服务实现类
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
    
    @Override
    public Page<Employee> listByCondition(EmployeeQueryDTO dto) {
        // 使用LambdaQueryWrapper构建条件查询
        return page(new Page<>(dto.getPageNum(), dto.getPageSize()),
            new LambdaQueryWrapper<Employee>()
                .like(StringUtils.isNotBlank(dto.getName()), Employee::getName, dto.getName())
                .eq(dto.getDepartment() != null, Employee::getDepartment, dto.getDepartment())
                .eq(dto.getStatus() != null, Employee::getStatus, dto.getStatus())
                .orderByDesc(Employee::getCreateTime)
        );
    }
}
Controller示例
java 复制代码
@RestController
@RequestMapping("/api/employee")
@RequiredArgsConstructor
public class EmployeeController {
    private final EmployeeService employeeService;

    @GetMapping("/page")
    public Result<Page<Employee>> pageList(EmployeeQueryDTO dto) {
        return Result.success(employeeService.listByCondition(dto));
    }

    @PostMapping
    public Result<Void> addEmployee(@RequestBody @Valid EmployeeDTO dto) {
        Employee employee = new Employee();
        BeanUtil.copyProperties(dto, employee);
        employeeService.save(employee);
        return Result.success();
    }

    @DeleteMapping("/{id}")
    public Result<Void> deleteEmployee(@PathVariable Long id) {
        // MP会自动处理逻辑删除
        employeeService.removeById(id);
        return Result.success();
    }
}
统一响应封装
java 复制代码
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
    private Integer code;
    private String msg;
    private T data;

    public static <T> Result<T> success(T data) {
        return new Result<>(200, "success", data);
    }

    public static Result<Void> success() {
        return success(null);
    }
}

前端核心实现(Vue3)

Axios封装
javascript 复制代码
// api/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus'

const service = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  timeout: 10000
})

// 请求拦截器(处理Token)
service.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`
  }
  return config
})

// 响应拦截器(统一处理错误)
service.interceptors.response.use(
  response => {
    const res = response.data
    if (res.code !== 200) {
      ElMessage.error(res.msg || 'Error')
      return Promise.reject(new Error(res.msg || 'Error'))
    }
    return res.data
  },
  error => {
    ElMessage.error(error.message || 'Request Error')
    return Promise.reject(error)
  }
)

export default service
API接口封装
javascript 复制代码
// api/employee.js
import request from './request'

export function getEmployeeList(params) {
  return request({
    url: '/api/employee/page',
    method: 'get',
    params
  })
}

export function addEmployee(data) {
  return request({
    url: '/api/employee',
    method: 'post',
    data
  })
}

export function deleteEmployee(id) {
  return request({
    url: `/api/employee/${id}`,
    method: 'delete'
  })
}
员工列表组件
vue 复制代码
<script setup>
import { ref, onMounted } from 'vue'
import { getEmployeeList, deleteEmployee } from '@/api/employee'

const tableData = ref([])
const loading = ref(false)
const pagination = ref({
  pageNum: 1,
  pageSize: 10,
  total: 0
})

const fetchData = async () => {
  loading.value = true
  try {
    const res = await getEmployeeList({
      ...pagination.value
    })
    tableData.value = res.records
    pagination.value.total = res.total
  } finally {
    loading.value = false
  }
}

const handleDelete = async (id) => {
  await deleteEmployee(id)
  ElMessage.success('删除成功')
  fetchData()
}

onMounted(() => {
  fetchData()
})
</script>

<template>
  <el-table :data="tableData" v-loading="loading">
    <el-table-column prop="name" label="姓名" />
    <el-table-column prop="department" label="部门" />
    <el-table-column prop="position" label="职位" />
    <el-table-column label="操作" width="180">
      <template #default="scope">
        <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
        <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
  
  <el-pagination
    v-model:current-page="pagination.pageNum"
    v-model:page-size="pagination.pageSize"
    :total="pagination.total"
    @current-change="fetchData"
    layout="total, prev, pager, next"
  />
</template>

MyBatis-Plus特性应用说明

自动填充功能

通过@TableField(fill = FieldFill.INSERT)等注解配合元对象处理器实现:

java 复制代码
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}
条件构造器最佳实践
java 复制代码
// 复杂查询示例
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.select(Employee::getId, Employee::getName, Employee::getDepartment)
       .likeRight(Employee::getName, "张")
       .between(Employee::getCreateTime, startDate, endDate)
       .orderByAsc(Employee::getDepartment)
       .orderByDesc(Employee::getCreateTime);

List<Employee> list = employeeMapper.selectList(wrapper);
逻辑删除实现原理

配置全局逻辑删除字段后,MP会自动在所有查询/删除操作中添加条件:

sql 复制代码
SELECT * FROM sys_employee WHERE is_deleted = 0
DELETE FROM sys_employee WHERE id = ? AND is_deleted = 0

实际执行的删除操作变为更新:

sql 复制代码
UPDATE sys_employee SET is_deleted = 1 WHERE id = ?
相关推荐
JAVA面经实录9171 小时前
Kafka 全套学习知识手册
java·kafka
绝知此事1 小时前
RabbitMQ 从入门到精通:Spring Boot 实战三部曲(三)—— 高级应用与性能优化
spring boot·rabbitmq·java-rabbitmq
源图客1 小时前
【亚马逊 SP-API 实战】Java 批量创建变体 Listing(父商品 + 子变体 + 独立图片)完整教程(亲测可用)
java·大数据·python
茫忙然1 小时前
Claude Code 接入 DeepSeek 或 多模型 教程(Linux)
java·linux·数据库
绝知此事1 小时前
RabbitMQ 从入门到精通:Spring Boot 实战三部曲(一)—— 基础核心与快速上手
spring boot·rabbitmq·java-rabbitmq
兰令水2 小时前
leecodecode【反前后指针】【2026.5.31打卡-java版本】
java·开发语言
AI人工智能+电脑小能手10 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
不爱洗脚的小滕10 小时前
【RAG】召回(Retrieval)与重排(Rerank)核心技术要点汇总
langchain·aigc·ai编程·rag
来杯@Java11 小时前
图书管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·mybatis·课程设计