项目：09-SpringBoot3+Vue3实现基本的增删改查功能

## 一：安装axios封装前后端对接数据工具
#### 1.在前端执行指令，安装axios
⭐用于前端给后端发送请求
```java
npm i axios -S
```
#### 2.封装前后端对接数据工具类
⭐用于拦截从后端返回的数据，先进行验证此次操作是否成功
在前端src-utils-request.js
```java
import axios from "axios";
import { ElMessage } from "element-plus";

const request = axios.create({
  baseURL: "http://localhost:8080",
  timeout: 30000 // 后台接口超时时间
});

// request 拦截器
// 可以自定义拦截请求时对请求做一些处理
request.interceptors.request.use((config) => {
      config.headers["Content-Type"] = "application/json;charset=utf-8";
      return config;
    },(error) => {
      return Promise.reject(error);
    });

// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
    (response) => {
      let res = response.data;
      // 将服务器返回的字符串类型数据转换成对象
      if (typeof res === "string") {
        res = res ? JSON.parse(res):res
      }
      return res;
    },
    (error) => {
      if (error.response.status === 404) {
        ElMessage.error("未找到请求接口！");
      } else if (error.response.status === 500) {
        ElMessage.error("系统错误，请稍后重试或联系管理员！");
      } else {
        console.error(error.message);
      }
      return Promise.reject(error);
    }
  )
  
  export default request;
```
#### 3.在后端设置跨域配置
```java
package com.example.common;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

// 跨域配置
@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 设置允许访问的域名
        corsConfiguration.addAllowedHeader("*"); // 设置允许的请求头
        corsConfiguration.addAllowedMethod("*"); // 设置允许的请求方法
        source.registerCorsConfiguration("/**", corsConfiguration); // 对接口配置跨域设置
        return new CorsFilter(source);
    }
}
```
## 二：分页查询数据
#### 1.table
```java
            <el-table :data="data.tableData" stripe>
                <el-table-column label="名称" prop="name"/>
                <el-table-column label="性别" prop="sex"/>
                <el-table-column label="工号" prop="no"/>
                <el-table-column label="年龄" prop="age"/>
                <el-table-column label="个人简介" prop="description" show-overflow-tooltip/>
                <el-table-column label="部门" prop="deptName"/>
            </el-table>
            <div style="margin-top: 15px">
              <el-pagination
              @size-change="load"
                  @current-change="load"
                  v-model:current-page="data.pageNum"
                  v-model:page-size="data.pageSize"
                  :page-sizes="[5, 10, 15, 20]"
                  background
                  layout="total, sizes, prev, pager, next, jumper"
                  :total="data.total"
              />
            </div>
```
#### 2.请求数据
```java
<script setup>
import { reactive } from 'vue';
import { Search } from '@element-plus/icons-vue';
import request from '@/utils/request';

const data = reactive({
    name:null,
    tableData:[],
    pageNum:1,
    pageSize:10,
    total:0 ,
})

const load  = () => {
  request.get('/employee/selectPage',{
    params:{
        pageNum:data.pageNum,
        pageSize:data.pageSize,
    }
  }).then(res => {
    data.tableData = res.data.list
    data.total = res.data.total
  })
}
load()
</script>
```
## 三：条件查询
⭐动态查询
```java
    <select id="selectAll"  resultType="com.example.entity.Employee">
        select * from employee
        <where>
            <if test="name != null">name like concat('%',#{name},'%')</if>
        </where>
        order by id desc
    </select>
```
## 四：新增数据
#### 1.新增弹窗组件，设置表单
```java
        <el-dialog title="员工信息" v-model="data.formVisible"  width="500">
          <el-form :model="data.form" label-width="80px" style="padding-right: 40px;padding-top: 20px">
            <el-form-item label="名称">
              <el-input v-model="data.form.name" autocomplete="off" placeholder="请输入名称" />
            </el-form-item>
            <el-form-item label="性别">
              <el-radio-group v-model="data.form.sex">
                <el-radio value="男" label="男"></el-radio>
                <el-radio value="女" label="女"></el-radio>
              </el-radio-group>
              <el-form-item label="工号">
              <el-input v-model="data.form.no" autocomplete="off" placeholder="请输入工号"/>
            </el-form-item>
            <el-form-item label="年龄">
              <el-input-number style="width: 180px" :min="18" v-model="data.form.age" autocomplete="off" placeholder="请输入年龄"/>
            </el-form-item>
            <el-form-item label="个人介绍">
              <el-input :rows="3" type="textarea" style="width: 180px" :min="18" v-model="data.form.description" autocomplete="off" placeholder="请输入个人介绍"/>
            </el-form-item>
            </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="data.formVisible = false">取消</el-button>
        <el-button type="primary" @click="save">保存</el-button>
      </div>
    </template>
  </el-dialog>
```
⭐通过handleAdd打开弹窗
```java
const handleAdd = () => {
    data.formVisible = true
    data.form = {}
}
```
#### 2.点击保存按钮，发起请求
```java
const save = () => {
    request.post('/employee/add',data.form).then(res =>{
        if(res.code === '200'){
            data.formVisible = false
           ElMessage.success('操作成功')
           load()
        }else{
            ElMessage.error(res.msg)
        }
     })
}
```
## 五：编辑数据
⭐步骤
①打开弹窗
②设置弹窗数据
③调用更新的接口
④重新加载表格数据
```java
const handleUpdate = (row) => {
    data.form = JSON.parse(JSON.stringify(row))  // 深拷贝一个新的对象 用于编辑 这样就不会影响行对象的数据了
    data.formVisible = true
}

const update = () => {
    request.put('/employee/update',data.form).then(res =>{ // 编辑的对象里面包含Id
        if(res.code === '200'){
            data.formVisible = false
           ElMessage.success('操作成功')
           load() // 更新后一定要重新加载最新的数据
        }else{
            ElMessage.error(res.msg)
        }
     })
}

const save = () => { // 在一个保存方法里面做两个操作，一个是新增，一个是编辑
     data.form.id ? update() : add()
}
```
## 六：删除数据
#### 1.单个删除
```java
const del = (id) => {
    ElMessageBox.confirm('删除数据后无法恢复，确认要删除吗？','删除确认',{type:'warning'}).then(() => {
        request.delete('employee/deleteById/' + id).then(res =>{
        if(res.code === '200'){
           ElMessage.success('操作成功')
           load() //删除后一定要重新加载最新的数据
        }else{
            ElMessage.error(res.msg)
        }
    })
    }).catch()
}
```
#### 2.批量删除
⭐后端接口必须使用RequestBody接收数组
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/f1ae006b-8c73-06aa-bff4-8347cf8dc7dc.png)

```java
const handleSelectionChange = (rows) => { //返回所有选中的行对象数组 
    console.log(rows)
    // 从选中的行数组里面取出所有行的Id组成一个新的数组
    data.ids = rows.map(row => row.id)
    console.log(data.ids)
}
```
```java
const delBatch = () => {
    if(data.ids.length === 0){
       ElMessage.warning('请选择数据')
       return
    }
    ElMessageBox.confirm('删除数据后无法恢复，确认要删除吗？','删除确认',{type:'warning'}).then(() => {
        request.delete('/employee/deleteBatch',{data:data.ids}).then(res => {
        if(res.code === '200'){
           ElMessage.success('操作成功')
           load()
        }else{
            ElMessage.error(res.msg)
        }
    })
    }).catch()
}
```