Vue3+SpringBoot全栈开发:从零实现增删改查与分页功能

前言

在现代化Web应用开发中,前后端分离架构已成为主流。本文将详细介绍如何使用Vue3作为前端框架,SpringBoot作为后端框架,实现一套完整的增删改查(CRUD)功能,包含分页查询、条件筛选等企业级特性。

技术栈介绍

  • 前端:Vue3 + Element Plus + Axios

  • 后端:SpringBoot + MyBatis-Plus

  • 构建工具:Vite (前端) + Maven (后端)

一、环境准备与项目搭建

1.1 前端项目初始化

bash

复制

下载

复制代码
npm init vue@latest vue3-springboot-crud
cd vue3-springboot-crud
npm install axios element-plus --save

1.2 后端项目搭建

使用Spring Initializr创建项目,添加以下依赖:

  • Spring Web

  • MyBatis Framework

  • Lombok

  • MySQL Driver

二、核心功能实现

2.1 跨域解决方案

前后端分离开发首要解决跨域问题,SpringBoot后端配置如下:

java

复制

下载

复制代码
@Configuration
public class CrossConfig {
    private static final long MAX_AGE = 24 * 60 * 60;

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setMaxAge(MAX_AGE);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

2.2 前端Axios封装

javascript

复制

下载

复制代码
import axios from "axios";
import { ElMessage } from 'element-plus'

const http = axios.create({
    baseURL: import.meta.env.VITE_API_BASE_URL,
    timeout: 50000
})

// 请求拦截器
http.interceptors.request.use(config => {
    config.headers['Content-Type'] = "application/json;charset=utf-8"
    const user = JSON.parse(localStorage.getItem("user") || '{}')
    if (user.token) {
        config.headers['Authorization'] = `Bearer ${user.token}`
    }
    return config
})

// 响应拦截器
http.interceptors.response.use(response => {
    if (response.data.code !== 200) {
        ElMessage.error(response.data.message)
    }
    return response.data
}, error => {
    ElMessage.error(error.message)
    return Promise.reject(error)
})

export default http

三、分页查询实现

3.1 后端分页逻辑

java

复制

下载

复制代码
@PostMapping("/list_page")
public Result<PageResult<User>> listPage(@RequestBody PageQuery<User> query) {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    if (StringUtils.isNotBlank(query.getEntity().getName())) {
        wrapper.like("name", query.getEntity().getName());
    }
    
    int total = userMapper.selectCount(wrapper);
    PageHelper.startPage(query.getCurrentPage(), query.getPageSize());
    List<User> list = userMapper.selectList(wrapper);
    
    return Result.success(new PageResult<>(total, list));
}

3.2 前端分页组件

vue

复制

下载

复制代码
<template>
  <div class="pagination-container">
    <el-pagination
      v-model:current-page="queryParams.currentPage"
      v-model:page-size="queryParams.pageSize"
      :page-sizes="[10, 20, 50, 100]"
      layout="total, sizes, prev, pager, next"
      :total="total"
      @size-change="handleQuery"
      @current-change="handleQuery"
    />
  </div>
</template>

<script setup>
import { reactive, ref } from 'vue'
import http from '@/utils/request'

const queryParams = reactive({
  currentPage: 1,
  pageSize: 10,
  name: ''
})

const total = ref(0)
const tableData = ref([])

const handleQuery = async () => {
  const res = await http.post('/user/list_page', queryParams)
  tableData.value = res.data.list
  total.value = res.data.total
}
</script>

四、完整CRUD实现

4.1 新增数据

java

复制

下载

复制代码
@PostMapping("/add")
public Result<String> addUser(@RequestBody User user) {
    user.setCreateTime(LocalDateTime.now());
    userMapper.insert(user);
    return Result.success("添加成功");
}

4.2 更新数据

java

复制

下载

复制代码
@PostMapping("/update")
public Result<String> updateUser(@RequestBody User user) {
    user.setUpdateTime(LocalDateTime.now());
    userMapper.updateById(user);
    return Result.success("更新成功");
}

4.3 删除数据

java

复制

下载

复制代码
@PostMapping("/delete")
public Result<String> deleteUser(@RequestBody List<Long> ids) {
    if (ids != null && !ids.isEmpty()) {
        userMapper.deleteBatchIds(ids);
    }
    return Result.success("删除成功");
}

五、前端界面优化

5.1 表格与表单组件

vue

复制

下载

复制代码
<template>
  <div class="app-container">
    <!-- 查询表单 -->
    <el-form :inline="true" class="search-form">
      <el-form-item label="用户名">
        <el-input v-model="queryParams.name" clearable @clear="handleQuery" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleQuery">查询</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    
    <!-- 操作按钮 -->
    <div class="operation-buttons">
      <el-button type="primary" @click="handleAdd">新增</el-button>
      <el-button type="danger" @click="handleBatchDelete">批量删除</el-button>
    </div>
    
    <!-- 数据表格 -->
    <el-table
      v-loading="loading"
      :data="tableData"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column label="操作" width="200">
        <template #default="scope">
          <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
          <el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <!-- 分页组件 -->
    <pagination
      v-show="total > 0"
      :total="total"
      v-model:page="queryParams.currentPage"
      v-model:limit="queryParams.pageSize"
      @pagination="handleQuery"
    />
    
    <!-- 新增/编辑对话框 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle">
      <el-form :model="form" :rules="rules" ref="formRef">
        <el-form-item label="姓名" prop="name">
          <el-input v-model="form.name" />
        </el-form-item>
        <el-form-item label="年龄" prop="age">
          <el-input-number v-model="form.age" :min="0" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitForm">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

六、性能优化建议

  1. 后端优化:

    • 使用MyBatis-Plus的分页插件替代手动分页

    • 添加Redis缓存高频访问数据

    • 对大数据量查询添加索引

  2. 前端优化:

    • 使用防抖处理频繁查询

    • 添加表格加载状态

    • 实现数据懒加载

javascript

复制

下载

复制代码
// 防抖处理示例
import { debounce } from 'lodash-es'

const debouncedQuery = debounce(handleQuery, 500)

七、常见问题解决

  1. 跨域问题:确保后端正确配置CORS,前端请求地址正确

  2. 分页失效:检查分页参数是否正确传递,后端SQL是否正确拼接

  3. 数据更新不及时:在增删改操作后重新查询数据

  4. 批量操作失败:检查后端是否支持批量操作,参数格式是否正确

结语

本文详细介绍了基于Vue3和SpringBoot的全栈CRUD开发流程,涵盖了从基础查询到复杂分页的实现,以及前后端交互的最佳实践。读者可以根据实际需求扩展更多功能,如表单验证、文件上传、权限控制等。欢迎交流。

相关推荐
CoderYanger5 小时前
Java EE 进阶:5. Spring IoC&DI(第三弹):Spring DI
java·开发语言·spring boot·spring·面试·java-ee·mvc
Thneonl5 小时前
Claude Code 频繁 Compacting?发布次日我根治了 2 个痛点
后端·rust
环境栈笔记6 小时前
指纹浏览器安卓怎么用?从运行位置到功能验收,先把三种方案分清
前端·人工智能·后端·自动化
小小张说故事7 小时前
Python 的 list 为什么能装下任何类型?拆开 PyObject* 数组,以及它让你多付了多少内存
后端·python
小蒜学长7 小时前
基于SpringBoot 框架的自媒体新闻系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·mysql数据库·自媒体新闻管理系统
Highcharts.js8 小时前
Highcharts 集成到 React 或 Vue 项目中时,如何高效地使用 TypeScript技巧?
vue.js·人工智能·react.js·typescript·前端框架·highcharts
IT_陈寒8 小时前
JavaScript实战技巧总结:深挖数组遍历的性能陷阱与实战解法
前端·人工智能·后端
余槐i8 小时前
PostgreSQL 加索引后查询反而更慢:优化器弃用索引的 3 种情形
spring boot·redis·mysql·postgresql·事务
Java后端的Ai之路17 小时前
CAS并发控制-从CPU指令到企业级乐观锁
vue.js·人工智能·python·cas·乐观锁
学长毕设17 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端