悠扬随风 发表于 2025-9-11 17:44:35

Spring Boot项目(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot前后端分离)

下载所在:

前端:https://download.csdn.net/download/2401_83418369/90811402
后端:https://download.csdn.net/download/2401_83418369/90811405
一、前端vue部门的搭建

这里直接看另一期刊的搭建Vue前端工程部门
前端vue+后端ssm项目_vue框架和ssm框架设置-CSDN博客

二、修改项目底子页面

修改App.vue页面

https://i-blog.csdnimg.cn/direct/af8cc36690a74af5bbabc6b0af515976.png
修改HomeView.vue 页面

https://i-blog.csdnimg.cn/direct/2e3c1eb29e884aaeb23696ae5d6709c7.png
删除HelloWorld.vue组件,新增一个组件Header

https://i-blog.csdnimg.cn/direct/09817d059b794b1983e93ced9e7ad09b.png
<script >
export default {
name:"Header"
}
</script>

<template>
<div style="height: 50px; line-height: 50px; border-bottom: 1px solid #ccc; display:
flex">
    <div style="width: 200px; padding-left: 30px; font-weight: bold; color: dodgerblue">后
      台管理</div>
    <div style="flex: 1"></div>
    <div style="width: 100px">下拉框</div>
</div>
</template>

<style scoped>

</style> https://i-blog.csdnimg.cn/direct/d9f637e858064d57ac0fb0b1417cd3dc.png
 创建全局样式global.css

https://i-blog.csdnimg.cn/direct/13861bb96cb3493b96120a08be9c53db.png
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
} 不要忘记在main.js文件中导入(导入才能生效) 

https://i-blog.csdnimg.cn/direct/de2c32c33aec4269a08960c2090cba88.png
导入 ElementPlus并运用
https://i-blog.csdnimg.cn/direct/8f806123c0cb41ca8cfe2cac4d13ad24.png
 快速开始 | Element Plus (element-plus.org)
测试一下:添加一个按钮 
https://i-blog.csdnimg.cn/direct/e0e3314d307643bfb03b8324b41dec82.png
https://i-blog.csdnimg.cn/direct/182282ba846d46e3a8cba0e23bdd4bbf.png
增长下拉列表的组件 
https://i-blog.csdnimg.cn/direct/3d198a10ab9642a295121182926ce296.png
<script >
export default {
name:"Header"
}
</script>

<template>
<div style="height: 50px;line-height: 50px;border-bottom: 1px solid #ccc;display: flex">
    <div style="width: 200px;padding-left: 30px;font-weight: bold;color:dodgerblue">后台管理</div>
    <div style="flex: 1"></div>
    <div style="width: 100px">
      <el-dropdown>
    <span class="el-dropdown-link">
      tom
      <el-icon class="el-icon--right">
      <arrow-down />
      </el-icon>
    </span>
      <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item>个人信息</el-dropdown-item>
            <el-dropdown-item>退出登录</el-dropdown-item>
          </el-dropdown-menu>
      </template>
      </el-dropdown>
    </div>
</div>
</template>

<style scoped>

</style> 导入到App.vue页面 
https://i-blog.csdnimg.cn/direct/bc563a15082546cc8d97f379daaa848c.png
<template>
<div>
<!--    引用组件-->
    <Header/>
    <div style="display: flex">
      <!--    侧边栏:将侧边栏放入盒子里面然后设置盒子的展示是弹性的-->
      <Aside/>
<!--      通过路由展示-->
      <router-view style="flex: 1"/>
    </div>
</div>
</template>
<style>
</style>
<script>
import Header from "@/components/Header.vue";
import Aside from "@/components/Aside.vue";
export default {
name:"Layout",
components:{
    Header,Aside
}
}
</script> 在HomeView.vue页面添加一个按钮 
https://i-blog.csdnimg.cn/direct/10769456d3864870841f5844db52dffe.png
https://i-blog.csdnimg.cn/direct/668c15ab7a504f5dae99035f91e47d67.png
添加 增长、查询的组件和一个表格
https://i-blog.csdnimg.cn/direct/51991ea2e527413686a6989baca212ea.png
<template>
<!--这个主要是用来路由到的页面,默认访问的页面-->
<div>
<!--添加按钮和查询框-->
<div style="margin: 10px 5px;display:inline-block">
    <el-button type="primary">新增</el-button>
    <el-button>其他</el-button>
</div>
<div style="display: inline-block">
    <el-input v-model="input" style="width: 150px" placeholder="请输入关键字" />
    <el-button type="success">提交</el-button>
</div>
<!--表格-->
<el-table :data="tableData" stripe style="width: 100%">
    <el-table-column sortable prop="date" label="日期" />
    <el-table-column prop="name" label="姓名"/>
    <el-table-column prop="address" label="地址" />
    <el-table-column fixed="right" label="操作" min-width="120">
      <template #default>
      <el-button link type="primary"@click="handleClick">
          删除
      </el-button>
      <el-button link type="primary">编辑</el-button>
      </template>
    </el-table-column>
</el-table>
</div>
</template>

<script>
// @ is an alias to /src
// import HelloWorld from '@/components/HelloWorld.vue'

export default {
name: 'HomeView',
components: {
},
//数据池的方法
data(){
    return{
      tableData:[
          {
            date: '2016-05-03',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles',
          },
    {
      date: '2016-05-02',
          name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
    },
    {
      date: '2016-05-04',
          name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
    },
    {
      date: '2016-05-01',
          name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
    },
]
    }
}
}
</script> https://i-blog.csdnimg.cn/direct/e795144454424c47890432c961273f1f.png
三、后端springboot环境搭建

紧张是设置pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.study</groupId>
    <artifactId>springboot_furn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
      <maven.compiler.source>8</maven.compiler.source>
      <maven.compiler.target>8</maven.compiler.target>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <parent>
      <artifactId>spring-boot-starter-parent</artifactId>
      <groupId>org.springframework.boot</groupId>
      <version>2.5.3</version>
    </parent>

    <dependencies>


      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
      </dependency>

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
      </dependency>


      <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
      </dependency>


      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
      </dependency>




      <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.17</version>
      </dependency>

      <!--      引入Mybatis-plus-->
      <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
      </dependency>


    </dependencies>

</project> 在application.yaml文件 设置数据源和端口

https://i-blog.csdnimg.cn/direct/f8760d099bb541978609eecebc162076.png
创建启动类 

https://i-blog.csdnimg.cn/direct/6d35a6010a064d0b9d1f0256cc7ecac7.png
四、添加家居

完成背景代码从 mapper -> service -> controller , 并对每层代码进行测试 , 到 controller 这一层,使用 Postman 发送 http 请求完成测试
 创建数据库和表

CREATE DATABASE springboot_vue;

USE springboot_vue;


CREATE TABLE furn(
`id` INT(11) PRIMARY KEY AUTO_INCREMENT, ## id
`name` VARCHAR(64) NOT NULL, ## 家居名
`maker` VARCHAR(64) NOT NULL, ## 厂商
`price` DECIMAL(11,2) NOT NULL, ## 价格
`sales` INT(11) NOT NULL, ## 销量
`stock` INT(11) NOT NULL ## 库存
);


INSERT INTO furn(`id` , `name` , `maker` , `price` , `sales` , `stock`)
VALUES(NULL , '北欧风格小桌子' , '熊猫家居' , 180 , 666 , 7);
INSERT INTO furn(`id` , `name` , `maker` , `price` , `sales` , `stock`)
VALUES(NULL , '简约风格小椅子' , '熊猫家居' , 180 , 666 , 7 );
INSERT INTO furn(`id` , `name` , `maker` , `price` , `sales` , `stock` )
VALUES(NULL , '典雅风格小台灯' , '蚂蚁家居' , 180 , 666 , 7 );
INSERT INTO furn(`id` , `name` , `maker` , `price` , `sales` , `stock` )
VALUES(NULL , '温馨风格盆景架' , '蚂蚁家居' , 180 , 666 , 7 );


SELECT * FROM furn; 创建 Result.java 该工具类用于返回效果(json 格式),这个工具类,在网上也可找到,直接拿来使用 , SSM 项目也用过类似的工具类

 https://i-blog.csdnimg.cn/direct/a1d9af1cdfd24223aafbf865a2554e8c.png  
package com.study.furn.utils;

public class Result<T> {
    private String code;
    private String msg;
    private T data;

    public Result() {
    }

    public Result(String code, String msg, T data) {
      this.code = code;
      this.msg = msg;
      this.data = data;
    }

    public String getCode() {
      return code;
    }

    public void setCode(String code) {
      this.code = code;
    }

    public String getMsg() {
      return msg;
    }

    public void setMsg(String msg) {
      this.msg = msg;
    }

    public T getData() {
      return data;
    }

    public void setData(T data) {
      this.data = data;
    }


    public Result(T data){
      this.data=data;
    }

    //返回成功的result不携带data数据
    public static Result success(){
      Result<Object> objectResult = new Result<>();
      objectResult.setCode("200");
      objectResult.setMsg("success");
      return objectResult;
    }
    //返回成功的result携带data数据,将静态方法定义为泛型方法,这个泛型方法和泛型类的泛型参数是独立的
    //静态方法的泛型类型参数与泛型类的类型参数名称相同但是编译器会进行区分
    public static<K> Result success(K data){
      Result<K> tResult = new Result<>(data);
      tResult.setCode("200");
      tResult.setMsg("success");
      return tResult;
    }


    //返回错误的result不携带data
    public static Result error(String code,String msg){
      Result<Object> objectResult = new Result<>();
      objectResult.setCode(code);
      objectResult.setMsg(msg);
      return objectResult;
    }

    //返回失败的result携带data数据
    public static<K> Result error(K data,String code,String msg){
      Result<K> tResult = new Result<>(data);
      tResult.setCode(code);
      tResult.setMsg(msg);
      return tResult;
    }

}
编写dao层 

https://i-blog.csdnimg.cn/direct/eaa697b21a284276b28fc3b487b50fb4.png
这里直接继续父接口BaseMapeer 
package com.study.furn.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.study.furn.bean.Furn;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface FurnMapper extends BaseMapper<Furn> {
}
在测试类中进行测试 :
https://i-blog.csdnimg.cn/direct/10dd41eaab194eaebea7d7d9de6391fb.png
https://i-blog.csdnimg.cn/direct/09781ebfdf894835b060c2072b16e808.png
编写Service层 

https://i-blog.csdnimg.cn/direct/a972d3e04407457bb419fbf67696c9de.png
package com.study.furn.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.study.furn.bean.Furn;

public interface FurnService extends IService<Furn> {
}
package com.study.furn.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.study.furn.bean.Furn;
import com.study.furn.dao.FurnMapper;
import com.study.furn.service.FurnService;
import org.springframework.stereotype.Service;

@Service
public class FurnServiceImpl extends ServiceImpl<FurnMapper, Furn> implements FurnService {
}
 测试类中进行测试:
https://i-blog.csdnimg.cn/direct/527603c2b6f248258abbdc63f6c90343.png
https://i-blog.csdnimg.cn/direct/09781ebfdf894835b060c2072b16e808.png
编写controller层 

https://i-blog.csdnimg.cn/direct/bdbeb866d15f4979a93e51b27bf3ec83.png
package com.study.furn.controller;


import com.study.furn.bean.Furn;
import com.study.furn.service.FurnService;
import com.study.furn.utils.Result;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
* 这里使用复合注解确保所有的方法返回给前端的数据都是json格式的数据
*/
@RestController
public class FurnController {

    @Resource
    private FurnService furnService;

    /**
   * 这是一个保存Furn对象的方法
   * @param furn
   * @return
   */
    @PostMapping("/save")
    public Result save(@RequestBody Furn furn){
      furnService.save(furn);
      return Result.success();
    }
}
使用Postman进行测试:
https://i-blog.csdnimg.cn/direct/9ae795a5da294aecba63780b68167c03.png
注意细节:

1、@RequestBody注解是将json格式的数据封装到方法的参数对象中,如果前端发送的表单数据/请求参数,不使用@RequestBody注解也会进行自动封装(还要注意的是请求头的Content-Type要和请求的数据类型匹配:表单的数据类型是application/x-www-form-urlencoded,json数据类型是application/json)
2、使用@RequestBody注解接收 JSON 时,若 ID 字段显式设为 null,可能导致 ORM(如 Hibernate)抛出非常,解决的方法是在id字段上添加@TableId(type = IdType.AUTO)注解
https://i-blog.csdnimg.cn/direct/746b89d5d74e4e2699bb901c01f4c962.png
在前端项目中添加表单组件

<template>
<!--这个主要是用来路由到的页面,默认访问的页面-->
<div>
    <!--添加按钮和查询框-->
    <div style="margin: 10px 5px;display:inline-block">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button>其他</el-button>
    </div>
    <div style="display: inline-block">
      <el-input v-model="input" style="width: 150px" placeholder="请输入关键字" />
      <el-button type="success">提交</el-button>
    </div>
    <!--表格-->
    <el-table :data="tableData" stripe style="width: 100%">
      <el-table-column sortable prop="date" label="日期" />
      <el-table-column prop="name" label="姓名"/>
      <el-table-column prop="address" label="地址" />
      <el-table-column fixed="right" label="操作" min-width="120">
      <template #default>
          <el-button link type="primary"@click="handleClick">
            删除
          </el-button>
          <el-button link type="primary">编辑</el-button>
      </template>
      </el-table-column>
    </el-table>


    <!--下面是对话框和表单
    <el-input v-model="form.name" style="width: 80%"></el-input>
    这里的form.name 表示form对象的属性name
    必须和后端的对象字段一样因为要将这些字段信息生成json格式打包给后端,
    这里的属性名可以动态生成,不需要在数据池里面编写

    -->
    <el-dialog
      title="提示"
      v-model="dialogVisible"
      width="30%">

      <el-form :model="form" label-width="120px">
      <!-- 家居名 -->
      <el-form-item label="家居名">
          <el-input v-model="form.name" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 厂商 -->
      <el-form-item label="厂商">
          <el-input v-model="form.maker" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 价格 -->
      <el-form-item label="价格">
          <el-input v-model="form.price" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 销量 -->
      <el-form-item label="销量">
          <el-input v-model="form.sales" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 库存 -->
      <el-form-item label="库存">
          <el-input v-model="form.stock" style="width: 80%"></el-input>
      </el-form-item>
      </el-form>

      <template #footer>
    <span class="dialog-footer">
<!--      直接写dialogVisible = false,因为只用一句,所以可以直接写在属性上-->
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="save">确定</el-button>
    </span>
      </template>
    </el-dialog>
</div>
</template>

<script>
// @ is an alias to /src
// import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
components: {
},
//数据池的方法
data(){
    return{
      //这里默认表单是不显示的
      dialogVisible:false,
      form:{},
      tableData:[
      {
          date: '2016-05-03',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-02',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-04',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-01',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      ]
    }
},
methods:{
    add(){
      this.dialogVisible=true;
      //但调用该方法后,将form对象的信息进行清除,
      // 因为表单里的数据和数据池的数据是双向绑定的如果填写了表单的数据那么数据池的数据就有了
      // 防止下次点击后出现上一次填写的数据,必须清空数据池的数据
      this.form={}
    }
}
}
</script> https://i-blog.csdnimg.cn/direct/7c37e5f8f1ea4c17b4534bc79d8665d8.png
在vue项目标终端中安装Axios

npm i axios -S https://i-blog.csdnimg.cn/direct/1c78be1f7c58416c80dbb97991df2ffe.png
编写request请求对象

//导入Axios包
import axios from "axios";
//通过Axios创建对象Request 发送请求到后端
const request = axios.create({
    timeout:5000
})
//Request拦截器加上统一的处理
//比如Content-Type,请求头中添加Content-Type表示请求体中的数据类型是json数据,
// 后端@RequestBody注解在内容协商中能匹配成功
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 (response.config.responseType==='blob'){
      return res
    }
    //如果是String,就转成json对象
    if (typeof res==='string'){
      res = res ? JSON.parse(res):res
    }
    return res
},error=>{
    return Promise.reject(error)
})

//导出Request对象,在其他组件就可以使用
export default request 在HomeView.vue页面中编写save方法发送json数据给后端

 https://i-blog.csdnimg.cn/direct/c1af312eea194893a2cf5216c3c3117c.png
<template>
<!--这个主要是用来路由到的页面,默认访问的页面-->
<div>
    <!--添加按钮和查询框-->
    <div style="margin: 10px 5px;display:inline-block">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button>其他</el-button>
    </div>
    <div style="display: inline-block">
      <el-input v-model="input" style="width: 150px" placeholder="请输入关键字" />
      <el-button type="success">提交</el-button>
    </div>
    <!--表格-->
    <el-table :data="tableData" stripe style="width: 100%">
      <el-table-column sortable prop="date" label="日期" />
      <el-table-column prop="name" label="姓名"/>
      <el-table-column prop="address" label="地址" />
      <el-table-column fixed="right" label="操作" min-width="120">
      <template #default>
          <el-button link type="primary"@click="handleClick">
            删除
          </el-button>
          <el-button link type="primary">编辑</el-button>
      </template>
      </el-table-column>
    </el-table>


    <!--下面是对话框和表单
    <el-input v-model="form.name" style="width: 80%"></el-input>
    这里的form.name 表示form对象的属性name
    必须和后端的对象字段一样因为要将这些字段信息生成json格式打包给后端,
    这里的属性名可以动态生成,不需要在数据池里面编写

    -->
    <el-dialog
      title="提示"
      v-model="dialogVisible"
      width="30%">

      <el-form :model="form" label-width="120px">
      <!-- 家居名 -->
      <el-form-item label="家居名">
          <el-input v-model="form.name" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 厂商 -->
      <el-form-item label="厂商">
          <el-input v-model="form.maker" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 价格 -->
      <el-form-item label="价格">
          <el-input v-model="form.price" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 销量 -->
      <el-form-item label="销量">
          <el-input v-model="form.sales" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 库存 -->
      <el-form-item label="库存">
          <el-input v-model="form.stock" style="width: 80%"></el-input>
      </el-form-item>
      </el-form>

      <template #footer>
    <span class="dialog-footer">
<!--      直接写dialogVisible = false,因为只用一句,所以可以直接写在属性上-->
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="save">确定</el-button>
    </span>
      </template>
    </el-dialog>
</div>
</template>

<script>
// @ is an alias to /src
import request from "@/utils/request"
export default {
name: 'HomeView',
components: {
},
//数据池的方法
data(){
    return{
      //这里默认表单是不显示的
      dialogVisible:false,
      form:{},
      tableData:[
      {
          date: '2016-05-03',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-02',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-04',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-01',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      ]
    }
},
methods:{
    add(){
      this.dialogVisible=true;
      //但调用该方法后,将form对象的信息进行清除,
      // 因为表单里的数据和数据池的数据是双向绑定的如果填写了表单的数据那么数据池的数据就有了
      // 防止下次点击后出现上一次填写的数据,必须清空数据池的数据
      this.form={}
    },
    save(){
      request.post("http://localhost:9090/save",this.form).then(
          response=>{
            console.log("response",response)
          }
      )
    }
}
}
</script>  这里碰到一个跨域请求的问题:
https://i-blog.csdnimg.cn/direct/4bb48edd6a424cb29ea7b451b216cc09.png
跨域请求问题是指由于浏览器的**同源策略(Same-Origin Policy)**限定,导致网页无法直接访问不同源(协议、域名、端口任一不同)的资源,从而引发的访问限定问题。
1. 跨域问题的本质

跨域问题的根源是浏览器的同源策略,该策略规定:


[*]同源条件:协议、域名、端口必须完全相同。例如,https://example.com与http://example.com(协议不同)、example.com与api.example.com(子域名不同)均属于跨域


[*]目标:防止恶意网站通过脚本窃取敏感数据(如Cookie、用户信息等),确保用户数据安全。
2. 跨域请求的触发场景

以下情况会触发跨域限定:

[*]Ajax/Fetch请求:前端通过JavaScript发起的HTTP请求目标不同源的服务端接口。
[*]资源加载:跨域加载图片、CSS、JavaScript文件等静态资源。
[*]Web API调用:如调用第三方API(如支付接口、地图服务)时,若未设置CORS则会被拦截。
3. 跨域问题的表现

浏览器拦截:即使请求乐成发送到服务端并返回数据,浏览器仍会拦截响应,导致前端无法获取效果。
错误提示:常见控制台报错如 No 'Access-Control-Allow-Origin' header is present
解决方法:代理服务器



[*]原理:前端请求同源代理服务器,由代理转发请求至目标服务器,规避浏览器限定。常用工具如Nginx或后端框架(如Spring Boot)的代理设置
在vue.config.js文件中添加代理 

https://i-blog.csdnimg.cn/direct/47cd86ebd6b04da7b3ea56d0cad0d0b3.png
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})

module.exports={
devServer:{
    port:10000 ,//启动端口
    // 设置代理
    proxy:{
      '/api':{ //设置拦截器,拦截器的格式 斜杆+名字   拦截规则:匹配所有以/api开头的请求路径
      target:'http://localhost:9090', //目标服务器地址:将匹配的请求转发到http://localhost:9090
      changeOrigin:true, //设置同源
      pathRewrite:{ //路径重写
          '/api':'' //api被替换为空,前端统一使用代理前缀(如 /api),但后端接口路径不含该前缀
          //前端请求:/api/user/list
          //实际转发:http://backend.com/user/list
          //    /api 这部分被 target的路径代替
      }
      }
    }
}
} 在HomeView.vue页面中进行修改 

https://i-blog.csdnimg.cn/direct/180841b1fe3a46748761a77bb3768422.png
<template>
<!--这个主要是用来路由到的页面,默认访问的页面-->
<div>
    <!--添加按钮和查询框-->
    <div style="margin: 10px 5px;display:inline-block">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button>其他</el-button>
    </div>
    <div style="display: inline-block">
      <el-input v-model="input" style="width: 150px" placeholder="请输入关键字" />
      <el-button type="success">提交</el-button>
    </div>
    <!--表格-->
    <el-table :data="tableData" stripe style="width: 100%">
      <el-table-column sortable prop="date" label="日期" />
      <el-table-column prop="name" label="姓名"/>
      <el-table-column prop="address" label="地址" />
      <el-table-column fixed="right" label="操作" min-width="120">
      <template #default>
          <el-button link type="primary"@click="handleClick">
            删除
          </el-button>
          <el-button link type="primary">编辑</el-button>
      </template>
      </el-table-column>
    </el-table>


    <!--下面是对话框和表单
    <el-input v-model="form.name" style="width: 80%"></el-input>
    这里的form.name 表示form对象的属性name
    必须和后端的对象字段一样因为要将这些字段信息生成json格式打包给后端,
    这里的属性名可以动态生成,不需要在数据池里面编写

    -->
    <el-dialog
      title="提示"
      v-model="dialogVisible"
      width="30%">

      <el-form :model="form" label-width="120px">
      <!-- 家居名 -->
      <el-form-item label="家居名">
          <el-input v-model="form.name" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 厂商 -->
      <el-form-item label="厂商">
          <el-input v-model="form.maker" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 价格 -->
      <el-form-item label="价格">
          <el-input v-model="form.price" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 销量 -->
      <el-form-item label="销量">
          <el-input v-model="form.sales" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 库存 -->
      <el-form-item label="库存">
          <el-input v-model="form.stock" style="width: 80%"></el-input>
      </el-form-item>
      </el-form>

      <template #footer>
    <span class="dialog-footer">
<!--      直接写dialogVisible = false,因为只用一句,所以可以直接写在属性上-->
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="save">确定</el-button>
    </span>
      </template>
    </el-dialog>
</div>
</template>

<script>
// @ is an alias to /src
import request from "@/utils/request"
export default {
name: 'HomeView',
components: {
},
//数据池的方法
data(){
    return{
      //这里默认表单是不显示的
      dialogVisible:false,
      form:{},
      tableData:[
      {
          date: '2016-05-03',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-02',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-04',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      {
          date: '2016-05-01',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
      },
      ]
    }
},
methods:{
    add(){
      this.dialogVisible=true;
      //但调用该方法后,将form对象的信息进行清除,
      // 因为表单里的数据和数据池的数据是双向绑定的如果填写了表单的数据那么数据池的数据就有了
      // 防止下次点击后出现上一次填写的数据,必须清空数据池的数据
      this.form={}
    },
    save(){
      request.post("/api/save",this.form).then(
          response=>{
            console.log("response",response)
            this.dialogVisible=false
          }
      )
    }
}
}
</script>
1. 代理机制的核心逻辑

通过将浏览器发起的跨域请求 转发到同源的后端代理服务,再由代理服务转发到现实目标服务器,从而绕过浏览器的同源策略限定。具体流程如下:

[*]前端请求路径:前端代码向同源所在(如 http://localhost:10000/api/data)发送请求。
[*]代理拦截:webpack-dev-server 根据 /api 规则拦截请求,更换目标所在为 http://localhost:9090/data(通过 pathRewrite 移除 /api 前缀)。
[*]服务端转发:代理服务将请求转发到目标服务器,并返回响应给前端。
[*]浏览器无感知:浏览器始终以为请求来自同源(localhost:10000),因此不会触发跨域拦截
过程:浏览器发送请求到vue,vue中进行拦截请求更换目标所在再请求到后端,后端响应数据到前端 
2. 关键设置项的作用

(1)target: 'http://localhost:9090'



[*]功能:指定目标服务器的真实所在,告知代理将请求转发至此所在。
[*]本质:将前端路径中的 /api 更换为 http://localhost:9090,实现请求重定向
2)changeOrigin: true



[*]作用:修改请求头中的 Host 和 Origin 为目标服务器所在(localhost:9090),使目标服务器以为请求来自合法源。
[*]须要性:部门服务器会验证请求来源,若未设置此参数,目标服务器可能因 Host 不匹配而拒绝请求
3)pathRewrite: { '/api': '' }



[*]功能:重写请求路径,移除前端添加的 /api 前缀。例如,/api/user 将被改写为 /user,确保目标接口路径正确。
[*]灵活性:答应前端同一使用代理前缀,后端接口无需修改即可适配
3. 代理为何能绕过跨域限定?

(1)浏览器同源策略的规避



[*]浏览器视角:所有请求均指向当地开发服务器(如 localhost:10000),未触发跨域规则。
[*]现实路径:代理服务器作为中间层,将请求转发至外部目标服务器(localhost:9090),而 服务器间通讯不受浏览器同源策略限定
4. 与其他方案的对比


方案上风局限性代理服务器无需后端配合修改,恰当当地开发调试;设置简单灵活仅适用于开发环境,生产环境需通过Nginx等实当代理CORS标准化解决方案,支持所有HTTP方法需后端设置响应头,对第三方API无法控制JSONP兼容老旧浏览器仅支持GET请求,存在安全风险 5. 注意事项



[*]仅限开发环境:代理设置通常在 webpack.config.js 或 vue.config.js 中设置,不适用于生产环境。生产环境需通过Nginx反向代理或后端服务处理跨域
[*]复杂路径匹配:可通过正则表达式界说更灵活的代理规则(如 /api/** 匹配多级路径),满足复杂接口需求
 进行测试:
https://i-blog.csdnimg.cn/direct/66718dc5979f4b97b1d5cffe9671080f.png
https://i-blog.csdnimg.cn/direct/4e138e112a4c44acb72cb99cdb7eb59d.png
五、显示家居信息

完成背景代码从 mapper -> service -> controller , 并对每层代码进行测试 , 到 controller 这一层,使用 Postman 发送 http 请求完成测试,由于mybatis-plus已经提供了父接口的方法,所以不须要再编写查询方法
在controller层添加查询方法 

https://i-blog.csdnimg.cn/direct/a1e6acae147a42d3b6e09b8db986d7f7.png
使用Postman进行测试

https://i-blog.csdnimg.cn/direct/67cf46f3b9324c529fe9466ed766b75d.png

在前端vue项目中修改,先清空数据池中tableData中的数据

https://i-blog.csdnimg.cn/direct/3197f0826ff1400295dc3dda22a36e20.png
表格部门的字段进行修改 

https://i-blog.csdnimg.cn/direct/0d96c88cf79249709bada38f2723e15d.png
下面是Template标签 的组件

<template>
<!--这个主要是用来路由到的页面,默认访问的页面-->
<div>
    <!--添加按钮和查询框-->
    <div style="margin: 10px 5px;display:inline-block">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button>其他</el-button>
    </div>
    <div style="display: inline-block">
      <el-input v-model="input" style="width: 150px" placeholder="请输入关键字" />
      <el-button type="success">提交</el-button>
    </div>
    <!--表格
    :data="tableData" 单向渲染数据,从数据池的data数据池的tableData字段里获取数据,
    <=> v-bind:data   -->
    <el-table :data="tableData" stripe style="width: 100%">
      <el-table-column sortable prop="id" label="ID" />
      <el-table-column prop="name" label="家居名"/>
      <el-table-column prop="maker" label="厂家" />
      <el-table-column prop="price" label="价格" />
      <el-table-column prop="sales" label="销量" />
      <el-table-column prop="stock" label="库存" />
      <el-table-column fixed="right" label="操作" min-width="120">
      <template #default>
          <el-button link type="primary"@click="handleClick">
            删除
          </el-button>
          <el-button link type="primary">编辑</el-button>
      </template>
      </el-table-column>
    </el-table>


    <!--下面是对话框和表单
    <el-input v-model="form.name" style="width: 80%"></el-input>
    这里的form.name 表示form对象的属性name
    必须和后端的对象字段一样因为要将这些字段信息生成json格式打包给后端,
    这里的属性名可以动态生成,不需要在数据池里面编写

    -->
    <el-dialog
      title="提示"
      v-model="dialogVisible"
      width="30%">

      <el-form :model="form" label-width="120px">
      <!-- 家居名 -->
      <el-form-item label="家居名">
          <el-input v-model="form.name" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 厂商 -->
      <el-form-item label="厂商">
          <el-input v-model="form.maker" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 价格 -->
      <el-form-item label="价格">
          <el-input v-model="form.price" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 销量 -->
      <el-form-item label="销量">
          <el-input v-model="form.sales" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 库存 -->
      <el-form-item label="库存">
          <el-input v-model="form.stock" style="width: 80%"></el-input>
      </el-form-item>
      </el-form>

      <template #footer>
    <span class="dialog-footer">
<!--      直接写dialogVisible = false,因为只用一句,所以可以直接写在属性上-->
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="save">确定</el-button>
    </span>
      </template>
    </el-dialog>
</div>
</template> 添加list方法

https://i-blog.csdnimg.cn/direct/09035c8e79f0496ea76dea835cc42914.png
https://i-blog.csdnimg.cn/direct/5c0318893c334c2a9c37df420b9351c6.png
将data字段的数据添补到数据池中

注意response拦截器进行了拦截处理:将字符串转成json格式的对象,并且将变量进行赋值
<template>
<!--这个主要是用来路由到的页面,默认访问的页面-->
<div>
    <!--添加按钮和查询框-->
    <div style="margin: 10px 5px;display:inline-block">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button>其他</el-button>
    </div>
    <div style="display: inline-block">
      <el-input v-model="input" style="width: 150px" placeholder="请输入关键字" />
      <el-button type="success">提交</el-button>
    </div>
    <!--表格
    :data="tableData" 单向渲染数据,从数据池的data数据池的tableData字段里获取数据,
    <=> v-bind:data   -->
    <el-table :data="tableData" stripe style="width: 100%">
      <el-table-column sortable prop="id" label="ID" />
      <el-table-column prop="name" label="家居名"/>
      <el-table-column prop="maker" label="厂家" />
      <el-table-column prop="price" label="价格" />
      <el-table-column prop="sales" label="销量" />
      <el-table-column prop="stock" label="库存" />
      <el-table-column fixed="right" label="操作" min-width="120">
      <template #default>
          <el-button link type="primary"@click="handleClick">
            删除
          </el-button>
          <el-button link type="primary">编辑</el-button>
      </template>
      </el-table-column>
    </el-table>


    <!--下面是对话框和表单
    <el-input v-model="form.name" style="width: 80%"></el-input>
    这里的form.name 表示form对象的属性name
    必须和后端的对象字段一样因为要将这些字段信息生成json格式打包给后端,
    这里的属性名可以动态生成,不需要在数据池里面编写

    -->
    <el-dialog
      title="提示"
      v-model="dialogVisible"
      width="30%">

      <el-form :model="form" label-width="120px">
      <!-- 家居名 -->
      <el-form-item label="家居名">
          <el-input v-model="form.name" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 厂商 -->
      <el-form-item label="厂商">
          <el-input v-model="form.maker" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 价格 -->
      <el-form-item label="价格">
          <el-input v-model="form.price" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 销量 -->
      <el-form-item label="销量">
          <el-input v-model="form.sales" style="width: 80%"></el-input>
      </el-form-item>

      <!-- 库存 -->
      <el-form-item label="库存">
          <el-input v-model="form.stock" style="width: 80%"></el-input>
      </el-form-item>
      </el-form>

      <template #footer>
    <span class="dialog-footer">
<!--      直接写dialogVisible = false,因为只用一句,所以可以直接写在属性上-->
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="save">确定</el-button>
    </span>
      </template>
    </el-dialog>
</div>
</template><script>//导入组件import request from "@/utils/request";export default {name: 'HomeView',components: {},//数据池的方法data(){    return{      //这里默认表单是不显示的      dialogVisible:false,      form:{},      tableData:[]    }},//钩子函数, created()函数调用后//数据池和方法池的数据都进行了初始化created() {    //调用list方法展示数据    this.list()},methods:{    list(){      request.get("/api/list").then(response=>{      this.tableData=response.data      })    },    add(){      this.dialogVisible=true;      //但调用该方法后,将form对象的信息进行清除,      // 防止下次点击后出现上一次填写的数据      this.form={}    },    save(){      request.post("/api/save",this.form).then(response=>{      console.log("response",response)      this.dialogVisible=false      //增长家居后调用查询      this.list()      })    },}}</script> https://i-blog.csdnimg.cn/direct/3bc41983352b423d8c0a605c2a8ec162.png
六、修改家居信息

完成背景代码从 mapper -> service -> controller , 并对每层代码进行测试 , 到 controller 这一层,使用 Postman 发送 http 请求完成测试,由于mybatis-plus已经提供了父接口的方法,所以不须要再编写修改方法
在controller层添加修改方法 

https://i-blog.csdnimg.cn/direct/0f6ec3f6ddf34b22a4c44d524cd81ab9.png
使用Postman进行测试 

https://i-blog.csdnimg.cn/direct/68a27c65d41b4611918de59ba1936b47.png
在前端vue项目中添加方法得到回显的数据

直接通过前端scope.row获取当前行的代理对象
https://i-blog.csdnimg.cn/direct/d623026caee144ac9bc8ad709752c400.png  https://i-blog.csdnimg.cn/direct/54e9c98235ed421f858c65b3038aec14.png
发现这是个代理对象,须要转换 Proxy 为原始对象

https://i-blog.csdnimg.cn/direct/088d9cb1d7354d6e8e9ca5809bc7e397.png
将代理对象转成原始对象,再将原始json对象绑定到 form表单中并进行展示

https://i-blog.csdnimg.cn/direct/b0e8839be0c845dfab989091244a15a9.png
https://i-blog.csdnimg.cn/direct/bb139952b451452aa61d472be87fbdf0.png
https://i-blog.csdnimg.cn/direct/598e9387331f4dc0a67502b2dfa781a2.png
save方法如下:根据form表单中是否有数据来区分要进行增长数据还是修改数据,同时根据响应的状态码来回显状态信息 
   save(){//添加、修改
      if (this.form.id){//如果表单中有数据id就是修改操作
      request.put("/api/update",this.form).then(
            response=>{
            if (response.code==="200"){//响应的状态码
                ElMessage({
                  type:"success",
                  message:"修改成功"
                })
            }else {
                ElMessage({
                  type:"error",
                  message:"修改失败"
                })
            }
            //刷新数据
            this.list()
            //关闭对话框
            this.dialogVisible=false
            }
      )


      }else {//添加
      request.post("/api/save",this.form).then(response=>{
          console.log("response",response)
          //增加家居后调用查询,刷新数据
          this.list()
          this.dialogVisible=false
      })
      }
    } https://i-blog.csdnimg.cn/direct/8ebbc406eb4d45b898eeb43e94b8bed2.png
补充回显数据的方式2:

将代理对象的id取出,然后将id发送给后端,后端根据id查询对应的Furn对象,然后再将对象进行回显
https://i-blog.csdnimg.cn/direct/5ddb09fcd50d47f3a29f49ea1a735185.png
https://i-blog.csdnimg.cn/direct/f5a4a07e98d74eada447f5845d15923d.png 在HomeView.vue页面中添加一个方法

https://i-blog.csdnimg.cn/direct/b1301cd2a54f44d5a0606e78c1e0cf8d.png

 https://i-blog.csdnimg.cn/direct/8e7a85132bd744d6b107f869cc0d102d.png
 同样能回显数据,这种方式回显才能确保数据库的真实数据https://i-blog.csdnimg.cn/direct/c30806139fe3465fab862542b5e5b237.png
七、删除家居信息 

完成背景代码从 mapper -> service -> controller , 并对每层代码进行测试 , 到 controller 这一层,使用 Postman 发送 http 请求完成测试,由于mybatis-plus已经提供了父接口的方法,所以不须要再编写删除方法
在controller层添加删除方法 

https://i-blog.csdnimg.cn/direct/88e44c2b17ed4c068d652c2780395ce1.png
使用Postman进行测试  

https://i-blog.csdnimg.cn/direct/9e3812c7952f46fbbbd7a6ca60561a3d.png
在前端vue实现删除的方法

将删除按钮进行修改
https://i-blog.csdnimg.cn/direct/0a24261ee40e49f68eae3169104003bb.png
https://i-blog.csdnimg.cn/direct/af5c108a15fc4249a920a30b48f487fc.png
实现删除的方法 

https://i-blog.csdnimg.cn/direct/c5eae85b472043499e8187c3947941ce.png
删除按钮: 
<!--      删除按钮 -->
          <el-popconfirm title="确认删除吗?" @confirm="handleDel(scope.row.id)">
            <template #reference>
            <el-button size="small" type="danger">删除</el-button>
            </template>
          </el-popconfirm> 删除方法: 
    handleDel(id){
   request.delete("/api/delete?id="+id).then(
         response=> {
         if (response.code === "200") {//响应的状态码
             ElMessage({
               type: "success",
               message: "删除成功"
             })
         } else {
             ElMessage({
               type: "error",
               message:"删除失败"
             })
         }
         //刷新数据
         this.list()
         }
   )
    } https://i-blog.csdnimg.cn/direct/daa25d584e42474eb03dd3edb279724f.png
八、分页显示列表

在设置类中设置分页拦截器

https://i-blog.csdnimg.cn/direct/de8fb7d259ff4698a2c2fe24e8d53e7f.png
package com.study.furn.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* 这是一个mybatis-plus配置类,在这里配置分页插件
*/
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
      MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
      //配置分页拦截器
      mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
      return mybatisPlusInterceptor;
    }
}
 在controller层添加分页方法 

https://i-blog.csdnimg.cn/direct/8a29ca71cb854de98d66ac69e50c71d2.png
使用Postman进行测试  

https://i-blog.csdnimg.cn/direct/d983b7609a03473eb48510218848c489.png
在表格下面添加导航栏组件 

https://i-blog.csdnimg.cn/direct/48619279bd6245f2bd0437f180f58b3f.png
<!--    添加分页导航-->
    <div style="margin:10px 0">
      <el-pagination
          @size-change="handlePageSizeChange"
          @current-change="handleCurrentChange"
          :current-page="currentPage"
          :page-sizes=""
          :page-size="pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
      >
      </el-pagination>
    </div> 数据池中绑定初始化数据 

https://i-blog.csdnimg.cn/direct/ff9e8d88ba0b40c0b2274ca69298cf13.png
https://i-blog.csdnimg.cn/direct/5482ae1fbd8442dc8525ebb5017de9e2.png
美满导航栏的两个方法,双向数据绑定 

https://i-blog.csdnimg.cn/direct/6333b6e267fb446ea6c391fdfb4bd2dd.png
修改list方法为分页方法

修改请求的路径并传两个参数(当前页,每页的数量)给后端,后端返回的total绑定到数据池 
https://i-blog.csdnimg.cn/direct/5531c9a369f5430c9516c6b0ea9c5b1a.png 
https://i-blog.csdnimg.cn/direct/758a71bd359f4bb9a645a6aa27224dd6.png
list方法如下 :
list(){
      // request.get("/api/list").then(response=>{
      //   this.tableData=response.data
      // })
      request.get("/api/page",{
       params:{
         pageNum:this.currentPage, //传给后端,当前页是第几页
         pageSize:this.pageSize//传给后端,当前页的数量
       }
      }).then(response=>{
      this.tableData=response.data.records
      this.total=response.data.total
      })
    }, https://i-blog.csdnimg.cn/direct/259342fdb3a2418e8de3792273ad5fdf.png
九、切换数据源为druid数据源

https://i-blog.csdnimg.cn/direct/cb4141a7b2bf4d6786bb92d0754701a7.png
新创建一个设置类 

package com.study.furn.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
* 数据源配置类
*/
@Configuration
public class DruidDataSourceConfig {


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
      DruidDataSource druidDataSource = new DruidDataSource();
      return druidDataSource;
    }
}
在application.yaml文件中设置也是可以的 

https://i-blog.csdnimg.cn/direct/e33873e5e904423096fd9a98063f7103.png
十、带条件查询分页显示列表

完成背景代码从 mapper -> service -> controller , 并对每层代码进行测试 , 到 controller 这一层,使用 Postman 发送 http 请求完成测试,由于mybatis-plus已经提供了父接口的方法,所以不须要再编写方法
在controller层添加方法 

https://i-blog.csdnimg.cn/direct/c226b947cd4443178c15536a91aaa9cb.png
使用Postman进行测试   

https://i-blog.csdnimg.cn/direct/9e37ef0fccf541ee84fd8a3fbf4dc62e.png
在查询输入框中绑定命据池,查询按钮中绑定点击方法

这里还是调用list方法
https://i-blog.csdnimg.cn/direct/ae61e0bb578d4cfdb04815d8a740ad87.png
https://i-blog.csdnimg.cn/direct/62a6e14ae02e41549eab5a68ac62cbd1.png
修改list方法 

https://i-blog.csdnimg.cn/direct/25f16c1b92864ed399b8a327df787a50.png
https://i-blog.csdnimg.cn/direct/ad5c8cf9e8434428bc71cf5eafaaa555.png
十一、添加家居表单美满前端校验

在数据池中添加校验规则

https://i-blog.csdnimg.cn/direct/92a8d7b13aa94986a8c511d7f0b6926e.png
      //校验规则
      rules:{
      name:[{
          required:true,message:"请输入家居名",trigger:"blur"
      }],
      maker:[{
          required:true,message:"请输入厂家名",trigger:"blur"
      }],
      price:[{
          required:true,message:"请输入价格",trigger:"blur"
      },{
          pattern:/^(\d*|0)(\.\d+)?$/ ,message: "请输入数字",trigger:"blur"
      }
      ],
      sales:[{
          required:true,message:"请输入销量",trigger:"blur"
      },{
          pattern:/^(\d*|0)$/ ,message: "请输入数字",trigger:"blur"
      }],
      stock:[{
          required:true,message:"请输入库存",trigger:"blur"
      },{
          pattern:/^(\d*|0)$/ ,message: "请输入数字",trigger:"blur"
      }]
      } 表单中绑定校验规则 

https://i-blog.csdnimg.cn/direct/df478b2f9e5c4f36914f38e84d2a6d57.png
https://i-blog.csdnimg.cn/direct/cce132b27f0e49c8b1cfcfb21f34c6d7.png
在点击确定按钮时进行校验,如果校验通过才发送请求到后端 

https://i-blog.csdnimg.cn/direct/4d0c6cef150f4fdd86d085d2c6f98fd1.png
清空上一次的校验 

https://i-blog.csdnimg.cn/direct/161cc3bd7b4c41968a8a3d14916992a4.png 
//清空上一次的校验
      this.$nextTick(() => {
      this.$refs['form'].resetFields();
      }); https://i-blog.csdnimg.cn/direct/3878cb28c56d49c090e058d0e235a371.png
十二、添加家居表单美满后端校验 

后端校验紧张是防止别人绕过前端校验直接发送save请求到后端
引入jsr303数据校验支持

记得刷新Maven
https://i-blog.csdnimg.cn/direct/0462aca086594262a7d424dc5223249e.png
使用注解对furn的字段进行校验 

https://i-blog.csdnimg.cn/direct/e6b64ee1ed0748af8ec1ad9a5c1f2a90.png
 使用Postman进行测试   

https://i-blog.csdnimg.cn/direct/001d5683603942ba95673a08973cd217.png
在数据池中添加一个后端校验对象 

https://i-blog.csdnimg.cn/direct/ff85b862a598460f94382a26cbf78ccc.png 在save方法中添加代码根据后端的状态码来处理

https://i-blog.csdnimg.cn/direct/730b67e1914b422b943cfca123e0804e.png
在表单中展示后端的校验信息 

https://i-blog.csdnimg.cn/direct/702dddc88c8142c7898e16b63b97d72e.png
清空上一次的后端校验信息 

https://i-blog.csdnimg.cn/direct/410b700b9f2b42fdb300f0cd94447279.png
https://i-blog.csdnimg.cn/direct/334d2febf9e2410685fa36cb9d3bd09d.png
总结: 

该项目使用了前后端分离,前端的主体框架Vue3+后端的底子框架Spring-Boot
1.前端技能栈: vue3 + Axios + ElementsPlus
2.后端技能栈:SpringBoot + MyBatis Plus
3.数据库-Mysql
4.项目依赖管理-Maven
5.分页-MyBatis Plus 分页插件
6.切换数据源DruidDataSources
7.项目前端我们使用到 request 和 response拦截器,并且我们解决了跨域问题
目前该项目还有很多bug,后续再美满...

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Spring Boot项目(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot前后端分离)