健身房预约系统SSM+Mybatis实现(二、增删改查的具体实现)

发布于:2025-08-17 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、环境搭建

项目搭建可以参考上篇博客:

https://blog.csdn.net/m0_72900498/article/details/150282255?spm=1001.2014.3001.5501

二、用户管理页面(纯展示无事件操作)

想要实现的大致效果:
在这里插入图片描述

即整个三面html是四个部分:查询条件的表单,创建修改删除查询等按钮、用于显示成员信息的表格、分页条。

先写出大体的区域框架结构。

在这里插入图片描述

Element-plus:
https://element-plus.org/zh-CN/component/table.html

0.三步走

三步骤 :写网页(复制粘贴自己改造 )、创建对象(根据具体 情况分析 ) 、引入相关库/依赖 (网站上面都提供了)自己按照需要修改即可
在这里插入图片描述
根据需要选择自己需要的样式即可,然后下面还有需要引入的库,一定要引入进去 ,不然无法生效

在这里插入图片描述
是否需要创建对象,创建对象的格式网站也已经在对应的地方提供:比如:
在这里插入图片描述

1.查询表单

Element-plus:
https://element-plus.org/zh-CN/component/form.html

在这里插入图片描述
想作为查询条件的是:ID、手机号、姓名、年龄、性别、地址 、出生日期范围

(1)书写页面代码 :

<!-- 查询条件区域:想作为查询条件的是:ID、姓名、手机号、性别、年龄、地址 、出生日期范围-->

  <div class="page-container">
    <!--行内样式、双向绑定数据模型formInline.prop:和后端字段绑定-->
    <el-form :inline="true" :model="formInline" >

      <el-form-item label="ID" prop="id">
        <el-input v-model="formInline.id" placeholder="请输入客户ID" style="width: 130px" clearable/>
      </el-form-item>

      <el-form-item label="姓名" prop="name">
        <el-input v-model="formInline.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
      </el-form-item>

      <el-form-item label="电话" prop="phone">
        <el-input v-model="formInline.phone" placeholder="请输入客户电话" clearable/>
      </el-form-item>

      <el-form-item label="性别"  prop="sex"  style="width: 120px">
        <el-select
            v-model="formInline.sex"
            clearable
        >
          <el-option label="不限" value="不限"  />
          <el-option label="" value="" />
          <el-option label="" value="" />
        </el-select>
      </el-form-item>

      <el-form-item label="年龄" prop="age">
        <el-input v-model="formInline.age" placeholder="请输入客户年龄" clearable/>
      </el-form-item>

      <el-form-item label="地址" prop="address">
        <el-input v-model="formInline.address" placeholder="请输入客户地址" clearable/>
      </el-form-item>

      <el-form-item label="出生日期">
        <el-date-picker
            v-model="formInline.birthdayRange"
            type="daterange"
            start-placeholder="起始日期"
            end-placeholder="终止日期"
        />
      </el-form-item>

    </el-form>
  </div>

(2)对应的js部分创建对象数据模型的绑定部分:

// 查询表单对象:双向绑定数据:浏览器输入(视图 )-数据模型:
//因为这个表单是接收数据的,所以我们创建对象的时候就要定义变量并且完成初始化操作。
let formInline = ref({
  id:null,
  name:null,
  phone:null,
  sex:null,
  age:null,
  address:null,
  birthdayRange:[]
})

(3)引入需要的库/依赖:

import { ref, onMounted } from 'vue'
import api from "@/utils/api.js";

上述部分目前的全部代码:

<template>
 <!-- 查询条件区域:想作为查询条件的是:ID、姓名、手机号、性别、年龄、地址 、出生日期范围-->

  <div class="page-container">
    <!--行内样式、双向绑定数据模型formInline.prop:和后端字段绑定-->
    <el-form :inline="true" :model="formInline" >

      <el-form-item label="ID" prop="id">
        <el-input v-model="formInline.id" placeholder="请输入客户ID" style="width: 130px" clearable/>
      </el-form-item>

      <el-form-item label="姓名" prop="name">
        <el-input v-model="formInline.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
      </el-form-item>

      <el-form-item label="电话" prop="phone">
        <el-input v-model="formInline.phone" placeholder="请输入客户电话" clearable/>
      </el-form-item>

      <el-form-item label="性别"  prop="sex"  style="width: 120px">
        <el-select
            v-model="formInline.sex"
            clearable
        >
          <el-option label="不限" value="不限"  />
          <el-option label="" value="" />
          <el-option label="" value="" />
        </el-select>
      </el-form-item>

      <el-form-item label="年龄" prop="age">
        <el-input v-model="formInline.age" placeholder="请输入客户年龄" clearable/>
      </el-form-item>

      <el-form-item label="地址" prop="address">
        <el-input v-model="formInline.address" placeholder="请输入客户地址" clearable/>
      </el-form-item>

      <el-form-item label="出生日期">
        <el-date-picker
            v-model="formInline.birthdayRange"
            type="daterange"
            start-placeholder="起始日期"
            end-placeholder="终止日期"
        />
      </el-form-item>

    </el-form>
  </div>

<!-- 按钮区-->
  <div>

  </div>

<!--  表格展示成员数据-->
  <div>

  </div>

<!--  分页条:-->
  <div>

  </div>
</template>

<!--CSS样式-->
<style>

</style>

<!--JS事件操作部分 :-->
<<script setup>
import { ref, onMounted } from 'vue'
import api from "@/utils/api.js";

// 查询表单对象:双向绑定数据:浏览器输入(视图 )-数据模型:
//因为这个表单是接收数据的,所以我们创建对象的时候就要定义变量并且完成初始化操作。
let formInline = ref({
  id:null,
  name:null,
  phone:null,
  sex:null,
  age:null,
  address:null,
  birthdayRange:[]
})

onMounted(async () => {
  let resp = await api({
    url: "members",//http://localhost:3000/api/后面实际解析的时候是http://localhost:8080/api/v1/members
    method: "get",
    params: {
      page: 1,
      limit: 10
    }
  });
  console.log(resp);
});
</script>

(4)效果展示

在这里插入图片描述

2.显示增删改查的按钮

https://element-plus.org/zh-CN/component/button.html

(1)书写页面代码 :

<!-- 按钮区-->
  <div>
    <div class="mb-4">
      <el-button type="primary" round>增加会员</el-button>
      <el-button type="success" round>修改会员</el-button>
      <el-button type="info" round>查询会员</el-button>
      <el-button type="danger" round>删除会员</el-button>
    </div>
  </div>

(2)不需要创建对象的原因

不需要再跟上面的表单一样去创建对象,原因
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(3)引入需要的库/依赖:

(4)效果展示

在这里插入图片描述

3.会员信息的数据表格展示

https://element-plus.org/zh-CN/component/table.html

(1)书写页面代码 :

<!-- 3.表格展示成员数据-->
  <div>
    <el-table
        :data="tableData"
        style="width: 100%"
        class="data-grid"
        border
        highlight-current-row
        show-header
        :header-cell-style="{
        background: '#E6A23C',
        color: 'white',
        fontWeight: 'bold',
        stripe
      }"
    >
      <el-table-column type="selection" width="160" align="center" fixed/>
      <el-table-column fixed prop="id" label="会员ID" width="160"/>
      <el-table-column fixed prop="name" label="姓名" width="130"/>
      <el-table-column prop="phone" label="电话" width="150"/>
      <el-table-column prop="age" label="年龄" width="120"/>
      <el-table-column prop="createTime" label="注册时间" width="180"/>
      <el-table-column prop="address" label="地址" width="250"/>
      <el-table-column prop="sex" label="性别" width="120"/>
      <el-table-column prop="remark" label="备注" width="260"/>
      <el-table-column prop="birthday" label="出生日期" min-width="180"/>
    </el-table>

  </div>

并添加CSS样式:

<!--CSS样式-->
<style>
.data-grid {
  margin-top: 6px;
}
</style>

(2)对应的js部分创建对象数据模型的绑定部分:

//3.数据显示表格对象 :
const tableData = ref()

(3)引入需要的库/依赖:

import { ref } from 'vue'

(4)效果展示

在这里插入图片描述

4.分页条展示

https://element-plus.org/zh-CN/component/pagination.html

(1)书写页面代码 :

  <!-- 4.分页条-->
  <div class="pagination">
    <el-pagination
        v-model:current-page="memberPi.pageNo"
        v-model:page-size="memberPi.pageSize"
        :page-sizes="[1,5,10,15,20]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="memberPi.total"
        class="member-pi"
        background
        @current-change="handlePageChange"
        @size-change="handleSizeChange"
    />
  </div>

(2)对应的js部分创建对象数据模型的绑定部分:

//4.分页条对象 :里面的数据是默认值
let memberPi = reactive({//reactive也是一个响应式对象 这个访问的时候不用.value
  pageNo: 1,
  pageSize: 10,
  total: 0
});

(3)引入需要的库/依赖:

import { ref } from 'vue'
import { reactive } from 'vue' // 必须导入 reactive

(4)效果展示

在这里插入图片描述

至此,基本的页面展示部分已经做完了。整体效果 :
在这里插入图片描述

然后剩下的就是从数据库查询数据响应给前端了。

三、前端发送请求+事件操作+后端响应

1.页面加载的时候实现数据展示和分页效果

具体实现:

(1)首先给 查询会员按钮 添加事件:也就是添加查询 方法

在这里插入图片描述

<!-- 2.按钮区-->
  <div>
    <div class="mb-4">
      <el-button type="primary" round>增加会员</el-button>
      <el-button type="success" round>修改会员</el-button>
      <el-button type="info" round @click="select()">查询会员</el-button>
      <el-button type="danger" round>删除会员</el-button>
    </div>
  </div>

(2)自定义查询方法 : 当组件挂载完毕之后触发:这样一打开页面就有数据

//当组件挂载完毕之后触发:这样一打开页面就有数据
onMounted(async () => {
  select();
});

具体的select()方法以及分页查询的实现:

// 查询方法
async function select(pageNo = 1, pageSize = 10) {
  let params = toRaw(formInline.value);

  if(params.birthdayRange) {
    params.birthdayFrom = params.birthdayRange[0];
    params.birthdayTo = params.birthdayRange[1];
    delete params.birthdayRange;
  }
  console.log(params);

  try {
    const resp = await api({
      url: "/members",
      method: "get",
      params: {
        pageNo,
        pageSize,
        ...params
      }
    });

    tableData.value = resp.data.records;
    memberPi.pageNo = resp.data.current;
    memberPi.pageSize = resp.data.size;
    memberPi.total = resp.data.total;
  } catch (error) {
    console.error("查询失败:", error);
  }
}

// 分页变化处理
const handlePageChange = (currentPage) => {
  memberPi.pageNo = currentPage;
  select(currentPage, memberPi.pageSize);
};

const handleSizeChange = (pageSize) => {
  memberPi.pageSize = pageSize;
  select(1, pageSize);
};

实现效果 :
在这里插入图片描述

上述效果的汇总代码

<template>
  <!-- 1.查询条件区域:想作为查询条件的是:ID、姓名、手机号、性别、年龄、地址 、出生日期范围-->
  <div class="page-container">
    <!--行内样式、双向绑定数据模型formInline.prop:和后端字段绑定-->
    <el-form :inline="true" :model="formInline">
      <el-form-item label="ID" prop="id">
        <el-input v-model="formInline.id" placeholder="请输入客户ID" style="width: 130px" clearable/>
      </el-form-item>

      <el-form-item label="姓名" prop="name">
        <el-input v-model="formInline.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
      </el-form-item>

      <el-form-item label="电话" prop="phone">
        <el-input v-model="formInline.phone" placeholder="请输入客户电话" clearable/>
      </el-form-item>

      <el-form-item label="性别" prop="sex" style="width: 160px">
        <el-select v-model="formInline.sex" clearable>
          <el-option label="不限" value="不限"/>
          <el-option label="" value=""/>
          <el-option label="" value=""/>
        </el-select>
      </el-form-item>

      <el-form-item label="年龄" prop="age">
        <el-input v-model="formInline.age" placeholder="请输入客户年龄" clearable/>
      </el-form-item>

      <el-form-item label="地址" prop="address">
        <el-input v-model="formInline.address" placeholder="请输入客户地址" clearable/>
      </el-form-item>

      <el-form-item label="出生日期">
        <el-date-picker
            v-model="formInline.birthdayRange"
            type="daterange"
            start-placeholder="起始日期"
            end-placeholder="终止日期"
        />
      </el-form-item>
    </el-form>
  </div>

  <!-- 2.按钮区-->
  <div>
    <div class="mb-4">
      <el-button type="primary" round>增加会员</el-button>
      <el-button type="success" round>修改会员</el-button>
      <el-button type="info" round @click="select()">查询会员</el-button>
      <el-button type="danger" round>删除会员</el-button>
    </div>
  </div>

  <!-- 3.表格展示成员数据-->
  <div>
    <el-table
        :data="tableData"
        style="width: 100%"
        class="data-grid"
        border
        highlight-current-row
        show-header
        :header-cell-style="{
        background: '#E6A23C',
        color: 'white',
        fontWeight: 'bold',
        stripe
      }"
    >
      <el-table-column type="selection" width="160" align="center" fixed/>
      <el-table-column fixed prop="id" label="会员ID" width="160"/>
      <el-table-column fixed prop="name" label="姓名" width="130"/>
      <el-table-column prop="phone" label="电话" width="150"/>
      <el-table-column prop="age" label="年龄" width="120"/>
      <el-table-column prop="createTime" label="注册时间" width="180"/>
      <el-table-column prop="address" label="地址" width="250"/>
      <el-table-column prop="sex" label="性别" width="120"/>
      <el-table-column prop="remark" label="备注" width="260"/>
      <el-table-column prop="birthday" label="出生日期" min-width="180"/>
    </el-table>

  </div>

  <!-- 4.分页条-->
  <div class="pagination">
    <el-pagination
        v-model:current-page="memberPi.pageNo"
        v-model:page-size="memberPi.pageSize"
        :page-sizes="[1,5,10,15,20]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="memberPi.total"
        class="member-pi"
        background
        @current-change="handlePageChange"
        @size-change="handleSizeChange"
    />
  </div>
</template>

<script setup>
import { reactive, ref, onMounted, toRaw } from 'vue'
import api from "@/utils/api.js";

const size = ref('default');
const disabled = ref(false);

// 查询表单对象
let formInline = ref({
  id: null,
  name: null,
  phone: null,
  sex: null,
  age: null,
  address: null,
  birthdayRange: []
});

// 表格数据对象:响应式对象
let tableData = ref([]);

// 分页配置
let memberPi = reactive({
  pageNo: 1,
  pageSize: 10,
  total: 0
});

// 查询方法
async function select(pageNo = 1, pageSize = 15) {
  let params = toRaw(formInline.value);

  if(params.birthdayRange) {
    params.birthdayFrom = params.birthdayRange[0];
    params.birthdayTo = params.birthdayRange[1];
    delete params.birthdayRange;
  }
  console.log(params);

  try {
    const resp = await api({
      url: "/members",
      method: "get",
      params: {
        pageNo,
        pageSize,
        ...params
      }
    });

    tableData.value = resp.data.records;
    memberPi.pageNo = resp.data.current;
    memberPi.pageSize = resp.data.size;
    memberPi.total = resp.data.total;
  } catch (error) {
    console.error("查询失败:", error);
  }
}

// 分页变化处理
const handlePageChange = (currentPage) => {
  memberPi.pageNo = currentPage;
  select(currentPage, memberPi.pageSize);
};

const handleSizeChange = (pageSize) => {
  memberPi.pageSize = pageSize;
  select(1, pageSize);
};

// 组件挂载时加载数据
onMounted(() => {
  select();
});
</script>

<style>
.data-grid {
  margin-top: 6px;
}

.pagination {
  margin-top: 20px;
  display: flex;
  justify-content: center;
}
</style>

2.重置功能 :

(1)添加重置按钮并绑定事件

  <!-- 2.按钮区-->
  <div>
    <div class="mb-4">
      <el-button type="primary" round>增加会员</el-button>
      <el-button type="success" round>修改会员</el-button>
      <el-button type="info" round @click="select()">查询会员</el-button>
      <el-button type="primary" round @click="reset">重置</el-button>
      <el-button type="danger" round>删除会员</el-button>
      
    </div>
  </div>

关于上面绑定事件,绑定方法加不加 ()的区别 :

简单理解就是需要传递参数加();
不需要传递参数不加 ()

//重置按钮:重置表单操作:将表单的值设为空即可
function reset() {
    formInline.value = {
      id: null,
      name: null,
      phone: null,
      sex: null,
      age: null,
      address: null,
      birthdayRange: []
  };
}

3.查询会员(完成条件查询)

逻辑是:当我们点击查询会员按钮的时候,能够通过不同的非空查询条件查询出来对应的会员信息。

首先前端传递的都是字符串,先将日期格式进行转换 :
在表单的出生日期 部分添加:

value-format="YYYY-MM-DD"

我们在页面加载部分显示会员信息数据部分已经给出了具体的实现

实现效果 :

在这里插入图片描述
这部分重点是前端 传递参数 ,后端正确的 接收到,更多问题 其实是 出现在了后端,后端响应部分的代码 :
https://blog.csdn.net/m0_72900498/article/details/150282255?spm=1001.2014.3001.5501

4.删除功能

(1)给表格添加ref创建实例:

// 声明表格引用
const tableRef = ref()

添加到表格里面:属性 部分:

ref="tableRef"

引入依赖:

import { ElMessage, ElMessageBox } from 'element-plus' // 必须添加

(2)给删除按钮绑定事件(方法)

//删除会员按钮:实现只选中一行数据
function remove() {
  let rows = tableRef.value.getSelectionRows();//通过实例获取选中的表格的是哪一行 
  if (rows.length === 0) {
    ElMessage.warning("请选中您要删除的行");//设置提示信息
  } else {
    ElMessageBox.confirm("是否确认删除选中的行?", "警告", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    }).then(() => {
      //执行操作
      let ids = rows.map(it => it.id);//获取选中的删除Id
      removeByIds(ids);//校验只选中一行成功之后,调用removeByIds方法真正删除,并传递要删除的会员的Id值
    }).catch(() => {
      //捕获之后 
    });
  }
}
async function removeByIds(ids) {
  let resp = await api({
    url: "/members",
    method: "delete",
    data: ids
  });

  if (resp.success) {
    ElMessage.success("删除操作成功,共删除" + resp.data + "条");
    select(); // 刷新表格
  } else {
    ElMessage.error("删除失败,请稍候再试或联系管理员");
  }
}

点击选中行事件:


function tblRowClick(row) {
  if (!row || !tableRef.value) return
  tableRef.value.toggleRowSelection(row)
}

效果:
在这里插入图片描述
具体的删除操作去数据库中查 :

servcie层方法

package com.study.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import java.util.List;

public interface MemberService {
    //查询全部客户
    Page<Member> findAll(Page<Member> page, MemberSearchBean msb);

    //删除操作:批量删除(多个--传集合:是客户Id也就是整型),返回受影响的行数
     int delete(List<Integer> ids);
}
package com.study.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import java.util.List;

public interface MemberService {
    //查询全部客户
    Page<Member> findAll(Page<Member> page, MemberSearchBean msb);

    //删除操作:批量删除(多个--传集合:是客户Id也就是整型),返回受影响的行数
     int delete(List<Integer> ids);
}

根据Id删除mybatis-plus底层已经提供了,直接调方法就行,所以不用写mapper层了

Controller层:

package com.study.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import com.study.service.MemberService;
import com.study.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("api/v1/members" )//接收前端的请求,路径与前端发送请求的路径一致
public class MemberController {
    private MemberService memberService;

    @Autowired//依赖注入:创建对象:
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
    //查询全部客户:
    @GetMapping
    public ResponseEntity<JsonResult<?>> findAll(
            @RequestParam(defaultValue = "1") Integer pageNo,
            @RequestParam(defaultValue = "15") Integer pageSize,
            MemberSearchBean msb){

        Page<Member> page = new Page<>(pageNo,pageSize);
        Page<Member> all = memberService.findAll(page, msb);
        return ResponseEntity.ok(JsonResult.success(all));
    }

    @DeleteMapping//删除操作
    public ResponseEntity<JsonResult<?>> delete(@RequestBody Integer[] ids){
        int count = memberService.delete(List.of(ids));
        if(count==0){
            return ResponseEntity.ok(JsonResult.fail("删除会员失败"));
        }
        else {
            return ResponseEntity.ok(JsonResult.success(count));
        }
    }
}

Service层:

package com.study.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import java.util.List;

public interface MemberService {
    //查询全部客户
    Page<Member> findAll(Page<Member> page, MemberSearchBean msb);

    //删除操作:批量删除(多个--传集合:是客户Id也就是整型),返回受影响的行数
     int delete(List<Integer> ids);
}
package com.study.service.impl;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.mapper.MemberMapper;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import com.study.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service//控制反转:创建对象
public class MemberServiceImpl implements MemberService {

    @Autowired
    private MemberMapper memberMapper;

    @Override
    public Page<Member> findAll(Page<Member> page, MemberSearchBean msb) {
        return memberMapper.findAll(page,msb);
    }

    @Override
    public int delete(List<Integer> ids) {
        return memberMapper.deleteByIds(ids);//注意选对方法
    }

}

在这里插入图片描述
效果:
在这里插入图片描述
在这里插入图片描述

5.新增功能

(1)点击新增按钮出现弹窗:也就是对话框
按照官网给的就行:

https://element-plus.org/zh-CN/component/dialog.html
在这里插入图片描述
在这里插入图片描述
都有,根据需要改就行了。

 <!--  5-增加会员:-->
  <div>
    <el-dialog v-model="dialogVisible" title="新增会员信息" width="500" draggable>
      <el-form-item label="ID" prop="id" v-if="false">
        <el-input v-model="formInline2.id" placeholder="请输入ID" style="width: 130px" clearable/>
      </el-form-item>

      <el-form-item label="姓名" prop="name">
        <el-input v-model="formInline2.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
      </el-form-item>

      <el-form-item label="电话" prop="phone">
        <el-input v-model="formInline2.phone" placeholder="请输入客户电话" clearable/>
      </el-form-item>

      <el-form-item label="年龄" prop="age">
        <el-input v-model="formInline2.age" placeholder="请输入客户年龄" clearable/>
      </el-form-item>

      <el-form-item label="注册时间">
        <el-date-picker
            v-model="formInline2.createTime"
            type="date"
            placeholder="注册日期"
            value-format="YYYY-MM-DD"
        />
      </el-form-item>

      <el-form-item label="地址" prop="address">
        <el-input v-model="formInline2.address" placeholder="请输入客户地址" clearable/>
      </el-form-item>

      <el-form-item label="性别" prop="sex" style="width: 160px">
        <el-select v-model="formInline2.sex" clearable>
          <el-option label="" value=""/>
          <el-option label="" value=""/>
        </el-select>
      </el-form-item>

      <el-form-item label="备注" prop="remark" :rows="4">
        <el-input v-model="formInline2.remark"
                  width="260px" placeholder="请输入客户信息备注" clearable/>
      </el-form-item>

      <el-form-item label="出生日期">
        <el-date-picker
            v-model="formInline2.birthday"
            type="date"
            placeholder="出生日期"

            value-format="YYYY-MM-DD"
        />
      </el-form-item>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="submitAdd">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>

在这里插入图片描述

这个弹窗成功显示了,且能够正常填写数据,接下来就是给确定和取消按钮 添加事件 ,当点击确定按钮的时候提交后台。

但是要先添加输入信息是否合法的校验:暂时不做,后面再完善

相关事件:

// 对话框控制
const dialogVisible = ref(false)
// 新增会员表单数据
let formInline2 = ref({
  id: null,
  name: null,
  phone: null,
  sex: null,
  age: null,
  address: null,
  birthday:null,
  createTime: null,
  remark: null
});

后端完成响应。

6.修改功能

// 对话框控制:修改页面
const dialogVisible2 = ref(false)
<el-dialog v-model="dialogVisible2" title="修改会员信息" width="500" draggable>
      <el-form :model="formInline3">
        <el-form-item label="ID" prop="id" v-if="false">
          <el-input v-model="formInline3.id" placeholder="请输入ID" style="width: 130px" clearable/>
        </el-form-item>

        <el-form-item label="姓名" prop="name">
          <el-input v-model="formInline3.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
        </el-form-item>

        <el-form-item label="电话" prop="phone">
          <el-input v-model="formInline3.phone" placeholder="请输入客户电话" clearable/>
        </el-form-item>

        <el-form-item label="年龄" prop="age">
          <el-input v-model="formInline3.age" placeholder="请输入客户年龄" clearable/>
        </el-form-item>

        <el-form-item label="注册时间">
          <el-date-picker
              v-model="formInline3.createTime"
              type="date"
              placeholder="注册日期"
              value-format="YYYY-MM-DD"
          />
        </el-form-item>

        <el-form-item label="地址" prop="address">
          <el-input v-model="formInline3.address" placeholder="请输入客户地址" clearable/>
        </el-form-item>

        <el-form-item label="性别" prop="sex" style="width: 160px">
          <el-select v-model="formInline3.sex" clearable>
            <el-option label="" value=""/>
            <el-option label="" value=""/>
          </el-select>
        </el-form-item>

        <el-form-item label="备注" prop="remark" :rows="4">
          <el-input v-model="formInline3.remark"
                    width="260px" placeholder="请输入客户信息备注" clearable/>
        </el-form-item>

        <el-form-item label="出生日期">
          <el-date-picker
              v-model="formInline3.birthday"
              type="date"
              placeholder="出生日期"
              value-format="YYYY-MM-DD"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible2 = false">取消</el-button>
          <el-button type="primary" @click="submitEdit">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
// 修改会员表单数据
let formInline3 = ref({
  id: null,
  name: null,
  phone: null,
  sex: null,
  age: null,
  address: null,
  birthday:null,
  createTime: null,
  remark: null
});

在这里插入图片描述

后端完成响应即可

四、增删改查的全部代码+前后端响应思路

1.全部代码

<template>
  <!-- 1.查询条件区域:想作为查询条件的是:ID、姓名、手机号、性别、年龄、地址 、出生日期范围-->
  <div class="page-container">
    <!--行内样式、双向绑定数据模型formInline.prop:和后端字段绑定-->
    <el-form :inline="true" :model="formInline">
      <el-form-item label="ID" prop="id">
        <el-input v-model="formInline.id" placeholder="请输入ID" style="width: 130px" clearable/>
      </el-form-item>

      <el-form-item label="姓名" prop="name">
        <el-input v-model="formInline.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
      </el-form-item>

      <el-form-item label="电话" prop="phone">
        <el-input v-model="formInline.phone" placeholder="请输入客户电话" clearable/>
      </el-form-item>

      <el-form-item label="性别" prop="sex" style="width: 160px">
        <el-select v-model="formInline.sex" clearable>
          <el-option label="不限" value="不限"/>
          <el-option label="" value=""/>
          <el-option label="" value=""/>
        </el-select>
      </el-form-item>

      <el-form-item label="年龄" prop="age">
        <el-input v-model="formInline.age" placeholder="请输入客户年龄" clearable/>
      </el-form-item>

      <el-form-item label="地址" prop="address">
        <el-input v-model="formInline.address" placeholder="请输入客户地址" clearable/>
      </el-form-item>

      <el-form-item label="出生日期">
        <el-date-picker
            v-model="formInline.birthdayRange"
            type="daterange"
            start-placeholder="起始日期"
            end-placeholder="终止日期"
            value-format="YYYY-MM-DD"
        />
      </el-form-item>
    </el-form>
  </div>

  <!-- 2.按钮区-->
  <div>
    <div class="mb-4">
      <el-button type="primary" round @click="openAddDialog">增加会员</el-button>
      <el-button type="success" round  @click="edit">修改会员</el-button>
      <el-button type="info" round @click="select()">查询会员</el-button>
      <el-button type="primary" round @click="reset">重置</el-button>
      <el-button type="danger" round @click="remove">删除会员</el-button>
    </div>
  </div>

  <!-- 3.表格展示成员数据-->
  <div>
    <el-table ref="tableRef" :data="tableData" style="width: 100%" class="data-grid"
              @row-click="tblRowClick()"  stripe
              border highlight-current-row show-header :header-cell-style="{
        background: '#5da6e6',
        color: 'white',
        fontWeight: 'bold',

      }"
    >
      <el-table-column type="selection" width="160" align="center" fixed height="160" name="custom-selection-col" />
      <el-table-column fixed prop="id" label="会员ID" width="160" height="230px"/>
      <el-table-column fixed prop="name" label="姓名" width="130"/>
      <el-table-column prop="phone" label="电话" width="150"/>
      <el-table-column prop="age" label="年龄" width="120"/>
      <el-table-column prop="createTime" label="注册时间" width="180"/>
      <el-table-column prop="address" label="地址" width="250"/>
      <el-table-column prop="sex" label="性别" width="120"/>
      <el-table-column prop="remark" label="备注" width="260"/>
      <el-table-column prop="birthday" label="出生日期" min-width="180"/>
    </el-table>

  </div>

  <!-- 4.分页条-->
  <div class="pagination">
    <el-pagination
        v-model:current-page="memberPi.pageNo"
        v-model:page-size="memberPi.pageSize"
        :page-sizes="[1,5,10,15,20]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="memberPi.total"
        class="member-pi"
        background
        @current-change="handlePageChange"
        @size-change="handleSizeChange"
    />
  </div>

  <!--  5-增加会员:-->
  <div>
    <el-dialog v-model="dialogVisible" title="新增会员信息" width="500" draggable>
      <el-form-item label="ID" prop="id" v-if="false">
        <el-input v-model="formInline2.id" placeholder="请输入ID" style="width: 130px" clearable/>
      </el-form-item>

      <el-form-item label="姓名" prop="name">
        <el-input v-model="formInline2.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
      </el-form-item>

      <el-form-item label="电话" prop="phone">
        <el-input v-model="formInline2.phone" placeholder="请输入客户电话" clearable/>
      </el-form-item>

      <el-form-item label="年龄" prop="age">
        <el-input v-model="formInline2.age" placeholder="请输入客户年龄" clearable/>
      </el-form-item>

      <el-form-item label="注册时间">
        <el-date-picker
            v-model="formInline2.createTime"
            type="date"
            placeholder="注册日期"
            value-format="YYYY-MM-DD"
        />
      </el-form-item>

      <el-form-item label="地址" prop="address">
        <el-input v-model="formInline2.address" placeholder="请输入客户地址" clearable/>
      </el-form-item>

      <el-form-item label="性别" prop="sex" style="width: 160px">
        <el-select v-model="formInline2.sex" clearable>
          <el-option label="" value=""/>
          <el-option label="" value=""/>
        </el-select>
      </el-form-item>

      <el-form-item label="备注" prop="remark" :rows="4">
        <el-input v-model="formInline2.remark"
                  width="260px" placeholder="请输入客户信息备注" clearable/>
      </el-form-item>

      <el-form-item label="出生日期">
        <el-date-picker
            v-model="formInline2.birthday"
            type="date"
            placeholder="出生日期"

            value-format="YYYY-MM-DD"
        />
      </el-form-item>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="submitAdd">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>

  <!--  6-修改会员:-->
  <div>
    <el-dialog v-model="dialogVisible2" title="修改会员信息" width="500" draggable>
      <el-form :model="formInline3">
        <el-form-item label="ID" prop="id" v-if="false">
          <el-input v-model="formInline3.id" placeholder="请输入ID" style="width: 130px" clearable/>
        </el-form-item>

        <el-form-item label="姓名" prop="name">
          <el-input v-model="formInline3.name" placeholder="请输入客户姓名" style="width: 160px" clearable/>
        </el-form-item>

        <el-form-item label="电话" prop="phone">
          <el-input v-model="formInline3.phone" placeholder="请输入客户电话" clearable/>
        </el-form-item>

        <el-form-item label="年龄" prop="age">
          <el-input v-model="formInline3.age" placeholder="请输入客户年龄" clearable/>
        </el-form-item>

        <el-form-item label="注册时间">
          <el-date-picker
              v-model="formInline3.createTime"
              type="date"
              placeholder="注册日期"
              value-format="YYYY-MM-DD"
          />
        </el-form-item>

        <el-form-item label="地址" prop="address">
          <el-input v-model="formInline3.address" placeholder="请输入客户地址" clearable/>
        </el-form-item>

        <el-form-item label="性别" prop="sex" style="width: 160px">
          <el-select v-model="formInline3.sex" clearable>
            <el-option label="" value=""/>
            <el-option label="" value=""/>
          </el-select>
        </el-form-item>

        <el-form-item label="备注" prop="remark" :rows="4">
          <el-input v-model="formInline3.remark"
                    width="260px" placeholder="请输入客户信息备注" clearable/>
        </el-form-item>

        <el-form-item label="出生日期">
          <el-date-picker
              v-model="formInline3.birthday"
              type="date"
              placeholder="出生日期"
              value-format="YYYY-MM-DD"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible2 = false">取消</el-button>
          <el-button type="primary" @click="submitEdit">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { reactive, ref, onMounted, toRaw } from 'vue'
import api from "@/utils/api.js";
import { ElMessage, ElMessageBox } from 'element-plus'

const size = ref('default');
const disabled = ref(false);

// 对话框控制:新增页面
const dialogVisible = ref(false)
// 对话框控制:修改页面
const dialogVisible2 = ref(false)

// 查询表单对象
let formInline = ref({
  id: null,
  name: null,
  phone: null,
  sex: null,
  age: null,
  address: null,
  birthdayRange: []
});

// 表格数据对象
let tableData = ref([]);

// 分页配置
let memberPi = reactive({
  pageNo: 1,
  pageSize: 15,
  total: 0
});

// 新增会员表单数据
let formInline2 = ref({
  id: null,
  name: null,
  phone: null,
  sex: null,
  age: null,
  address: null,
  birthday:null,
  createTime: null,
  remark: null
});

// 修改会员表单数据
let formInline3 = ref({
  id: null,
  name: null,
  phone: null,
  sex: null,
  age: null,
  address: null,
  birthday:null,
  createTime: null,
  remark: null
});

// 查询会员方法
async function select(pageNo = 1, pageSize = 15) {
  let params = toRaw(formInline.value);

  if(params.birthdayRange) {
    params.birthdayFrom = params.birthdayRange[0];
    params.birthdayTo = params.birthdayRange[1];
    delete params.birthdayRange;
  }

  try {
    const resp = await api({
      url: "/members",
      method: "get",
      params: {
        pageNo,
        pageSize,
        ...params
      }
    });

    tableData.value = resp.data.records;
    memberPi.pageNo = resp.data.current;
    memberPi.pageSize = resp.data.size;
    memberPi.total = resp.data.total;
  } catch (error) {
    console.error("查询失败:", error);
  }
}

// 分页变化处理
const handlePageChange = (currentPage) => {
  memberPi.pageNo = currentPage;
  select(currentPage, memberPi.pageSize);
};

const handleSizeChange = (pageSize) => {
  memberPi.pageSize = pageSize;
  select(1, pageSize);
};

// 重置表单
function reset() {
  formInline.value = {
    id: null,
    name: null,
    phone: null,
    sex: null,
    age: null,
    address: null,
    birthday:null
  };
}

// 表格操作
const tableRef = ref()

function tblRowClick(row) {
  if (!row || !tableRef.value) return
  tableRef.value.toggleRowSelection(row)
}

//删除会员按钮:实现只选中一行数据
function remove() {
  let rows = tableRef.value.getSelectionRows();//通过实例获取选中的表格的是哪一行
  if (rows.length === 0) {
    ElMessage.warning("请选中您要删除的行");//设置提示信息
  } else {
    ElMessageBox.confirm("是否确认删除选中的行?", "警告", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    }).then(() => {
      //执行操作
      let ids = rows.map(it => it.id);//获取选中的删除Id
      removeByIds(ids);//校验只选中一行成功之后,调用removeByIds方法真正删除,并传递要删除的会员的Id值
    }).catch(() => {
      //捕获之后
    });
  }
}

async function removeByIds(ids) {
  let resp = await api({
    url: "/members",
    method: "delete",
    data: ids
  });

  if (resp.success) {
    ElMessage.success("删除操作成功,共删除" + resp.data + "条");
    select(); // 刷新表格
  } else {
    ElMessage.error("删除失败,请稍候再试或联系管理员");
  }
}

// 打开新增对话框
function openAddDialog() {
  formInline2.value = {
    id: null,
    name: null,
    phone: null,
    sex: null,
    age: null,
    address: null,
    birthday:null,
    createTime: null,
    remark: null
  }
  dialogVisible.value = true
}

// 提交新增
async function submitAdd() {
  try {
    // 处理日期数据
    const params = {
      ...toRaw(formInline2.value),
      birthdayFrom: formInline2.value.birthdayRange?.[0],
      birthdayTo: formInline2.value.birthdayRange?.[1]
    }
    delete params.birthdayRange

    const resp = await api({
      url: "/members",
      method: "post",
      data: params
    })

    if (resp.success) {
      ElMessage.success("新增会员成功")
      dialogVisible.value = false
      select() // 刷新表格
    }
  } catch (error) {
    console.error("新增失败:", error)
    ElMessage.error("新增失败,请稍候再试")
  }
}
//新增表单对象
let memberFormRef = ref();
let mode = "add";//标志位

//修改按钮
function edit() {
  let rows = tableRef.value.getSelectionRows();
  if (rows.length === 0) {
    ElMessage.warning("请选中您要修改的行");
  } else if (rows.length > 1) {
    ElMessage.warning("您一次只能修改一行");
  } else {
    // 将选中的行数据填充到表单中
    formInline3.value = {
      ...rows[0]
    };
    dialogVisible2.value = true;
  }
}

//提交修改
async function submitEdit() {
  try {
    const resp = await api({
      url: "/members",
      method: "put",
      data: toRaw(formInline3.value)
    });

    if (resp.success) {
      ElMessage.success("修改会员信息成功");
      dialogVisible2.value = false;
      select(); // 刷新表格
    }
  } catch (error) {
    console.error("修改失败:", error);
    ElMessage.error("修改失败,请稍候再试");
  }
}
// 组件挂载时加载数据
onMounted(() => {
  select();
});
</script>

<style>
.data-grid {
  margin-top: 6px;
}

.pagination {
  margin-top: 20px;
  display: flex;
  justify-content: center;
}

.member-pi {
  margin-top: 6px;
}

</style>

2.前后端分离项目的响应思路

在前后端分离架构中,前端(Vue/React)和后端(Spring Boot)通过 RESTful API 进行交互,主要涉及 请求(Request) 和 响应(Response) 的处理。

1.前端发送请求

在这里插入图片描述
前端四种请求方式举例:

// GET 请求(带查询参数)
await api({
  url: "/members",
  method: "get",
  params: { pageNo: 1, pageSize: 10 }
});

// POST 请求(提交 JSON 数据)
await api({
  url: "/members",
  method: "post",
  data: { name: "张三", age: 25 }
});

// PUT 请求(修改数据,ID 在 URL 中)
await api({
  url: `/members/${id}`,
  method: "put",
  data: { name: "李四", age: 30 }
});

// DELETE 请求(删除数据)
await api({
  url: `/members/${id}`,
  method: "delete"
});

2.后端接收请求

在这里插入图片描述

@RestController
@RequestMapping("/api/v1/members")
public class MemberController {

    @GetMapping
    public ResponseEntity<JsonResult<?>> findAll(
        @RequestParam(defaultValue = "1") int pageNo,
        @RequestParam(defaultValue = "10") int pageSize
    ) {
        // 查询逻辑
    }

    @PostMapping
    public ResponseEntity<JsonResult<?>> add(@RequestBody Member member) {
        // 新增逻辑
    }

    @PutMapping("/{id}")
    public ResponseEntity<JsonResult<?>> edit(
        @PathVariable Integer id,
        @RequestBody Member member
    ) {
        // 修改逻辑
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<JsonResult<?>> delete(@PathVariable Integer id) {
        // 删除逻辑
    }
}

3.后端做出响应

后端返回响应
统一响应格式(推荐):

{
  "success": true,
  "code": 200,
  "message": "操作成功",
  "data": { ... }  // 业务数据
}

Spring Boot 返回方式:

@GetMapping
public ResponseEntity<JsonResult<?>> findAll() {
    List<Member> members = memberService.findAll();
    return ResponseEntity.ok(JsonResult.success(members));
}

@PostMapping
public ResponseEntity<JsonResult<?>> add(@RequestBody Member member) {
    boolean success = memberService.add(member);
    if (success) {
        return ResponseEntity.ok(JsonResult.success("新增成功"));
    } else {
        return ResponseEntity.ok(JsonResult.fail("新增失败"));
    }
}

4.前端处理响应

Axios 拦截器(统一处理错误):

// 响应拦截器(api.js)
axios.interceptors.response.use(
  (response) => {
    if (response.data.success) {
      return response.data; // 返回 data 部分
    } else {
      ElMessage.error(response.data.message || "操作失败");
      return Promise.reject(response.data);
    }
  },
  (error) => {
    ElMessage.error(error.response?.data?.message || "网络错误");
    return Promise.reject(error);
  }
);

javascript

async function loadMembers() {
  try {
    const resp = await api.get("/members");
    tableData.value = resp.data; // 获取后端返回的 data
  } catch (error) {
    console.error("加载失败:", error);
  }
}

5.常见问题以及解决方案

在这里插入图片描述

6.总结

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到