当前位置: 首页 > news >正文

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页面

修改HomeView.vue 页面

删除HelloWorld.vue组件,新增一个组件Header

<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>

 创建全局样式global.css

* {margin: 0;padding: 0;box-sizing: border-box;
}
不要忘记在main.js文件中导入(导入才能生效) 

导入 ElementPlus并运用

 快速开始 | Element Plus (element-plus.org)

测试一下:添加一个按钮 

增加下拉列表的组件 

<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页面 

<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页面添加一个按钮 

添加 增加、查询的组件和一个表格

<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>


三、后端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文件 配置数据源和端口

创建启动类 


四、添加家居

完成后台代码从 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 项目也用过类似的工具类

   

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不携带datapublic 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层 

这里直接继承父接口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> {
}

在测试类中进行测试 :

编写Service层 

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 {
}

 测试类中进行测试:

编写controller层 

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 {@Resourceprivate FurnService furnService;/*** 这是一个保存Furn对象的方法* @param furn* @return*/@PostMapping("/save")public Result save(@RequestBody Furn furn){furnService.save(furn);return Result.success();}
}

使用Postman进行测试:

注意细节:

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)注解

在前端项目中添加表单组件

<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-dialogtitle="提示"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>

在vue项目的终端中安装Axios

npm i axios -S

编写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数据给后端

 

<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-dialogtitle="提示"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>

 这里遇到一个跨域请求的问题:

跨域请求问题是指由于浏览器的**同源策略(Same-Origin Policy)**限制,导致网页无法直接访问不同源(协议、域名、端口任一不同)的资源,从而引发的访问限制问题。

1. 跨域问题的本质

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

  • 同源条件:协议、域名、端口必须完全相同。例如,https://example.comhttp://example.com(协议不同)、example.comapi.example.com(子域名不同)均属于跨域
  • 目的:防止恶意网站通过脚本窃取敏感数据(如Cookie、用户信息等),确保用户数据安全。

2. 跨域请求的触发场景

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

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

3. 跨域问题的表现

浏览器拦截:即使请求成功发送到服务端并返回数据,浏览器仍会拦截响应,导致前端无法获取结果。

错误提示:常见控制台报错如 No 'Access-Control-Allow-Origin' header is present

解决方法:代理服务器

  • 原理:前端请求同源代理服务器,由代理转发请求至目标服务器,规避浏览器限制。常用工具如Nginx或后端框架(如Spring Boot)的代理配置

在vue.config.js文件中添加代理 

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:9090changeOrigin:true, //设置同源pathRewrite:{ //路径重写'/api':'' //api被替换为空,前端统一使用代理前缀(如 /api),但后端接口路径不含该前缀//前端请求:/api/user/list//实际转发:http://backend.com/user/list//    /api 这部分被 target的路径代替}}}}
}

在HomeView.vue页面中进行修改 

<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-dialogtitle="提示"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. 代理机制的核心逻辑

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

  1. 前端请求路径:前端代码向同源地址(如 http://localhost:10000/api/data)发送请求。
  2. 代理拦截:webpack-dev-server 根据 /api 规则拦截请求,替换目标地址为 http://localhost:9090/data(通过 pathRewrite 移除 /api 前缀)。
  3. 服务端转发:代理服务将请求转发到目标服务器,并返回响应给前端。
  4. 浏览器无感知:浏览器始终认为请求来自同源(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/** 匹配多级路径),满足复杂接口需求

 进行测试:


五、显示家居信息

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

在controller层添加查询方法 

使用Postman进行测试

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

表格部分的字段进行修改 

下面是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-dialogtitle="提示"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方法

将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-dialogtitle="提示"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>


六、修改家居信息

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

在controller层添加修改方法 

使用Postman进行测试 

在前端vue项目中添加方法得到回显的数据

直接通过前端scope.row获取当前行的代理对象

  

发现这是个代理对象,需要转换 Proxy 为原始对象

将代理对象转成原始对象,再将原始json对象绑定到 form表单中并进行展示

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})}}

补充回显数据的方式2:

将代理对象的id取出,然后将id发送给后端,后端根据id查询对应的Furn对象,然后再将对象进行回显

 在HomeView.vue页面中添加一个方法

 

 同样能回显数据,这种方式回显才能确保数据库的真实数据


七、删除家居信息 

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

在controller层添加删除方法 

使用Postman进行测试  

在前端vue实现删除的方法

将删除按钮进行修改

实现删除的方法 

删除按钮: 

 <!--        删除按钮 --><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()})}


八、分页显示列表

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

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 {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();//配置分页拦截器mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return mybatisPlusInterceptor;}
}

 在controller层添加分页方法 

使用Postman进行测试  

在表格下面添加导航栏组件 

<!--    添加分页导航--><div style="margin:10px 0"><el-pagination@size-change="handlePageSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[5, 10]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"></el-pagination></div>

数据池中绑定初始化数据 

完善导航栏的两个方法,双向数据绑定 

修改list方法为分页方法

修改请求的路径并传两个参数(当前页,每页的数量)给后端,后端返回的total绑定到数据池 

 

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.recordsthis.total=response.data.total})},


九、切换数据源为druid数据源

新创建一个配置类 

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文件中配置也是可以的 


十、带条件查询分页显示列表

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

在controller层添加方法 

使用Postman进行测试   

在查询输入框中绑定数据池,查询按钮中绑定点击方法

这里还是调用list方法

修改list方法 


十一、添加家居表单完善前端校验

在数据池中添加校验规则

      //校验规则rules:{name:[{required:true,message:"请输入家居名",trigger:"blur"}],maker:[{required:true,message:"请输入厂家名",trigger:"blur"}],price:[{required:true,message:"请输入价格",trigger:"blur"},{pattern:/^([1-9]\d*|0)(\.\d+)?$/ ,message: "请输入数字",trigger:"blur"}],sales:[{required:true,message:"请输入销量",trigger:"blur"},{pattern:/^([1-9]\d*|0)$/ ,message: "请输入数字",trigger:"blur"}],stock:[{required:true,message:"请输入库存",trigger:"blur"},{pattern:/^([1-9]\d*|0)$/ ,message: "请输入数字",trigger:"blur"}]}

表单中绑定校验规则 

在点击确定按钮时进行校验,如果校验通过才发送请求到后端 

清空上一次的校验 

 

//清空上一次的校验this.$nextTick(() => {this.$refs['form'].resetFields();});


十二、添加家居表单完善后端校验 

后端校验主要是防止别人绕过前端校验直接发送save请求到后端

引入jsr303数据校验支持

记得刷新Maven

使用注解对furn的字段进行校验 

 使用Postman进行测试   

在数据池中添加一个后端校验对象 

 在save方法中添加代码根据后端的状态码来处理

在表单中展示后端的校验信息 

清空上一次的后端校验信息 


总结: 

该项目使用了前后端分离,前端的主体框架Vue3+后端的基础框架Spring-Boot

1.前端技术栈: vue3 + Axios + ElementsPlus

2.后端技术栈:SpringBoot + MyBatis Plus

3.数据库-Mysql

4.项目依赖管理-Maven

5.分页-MyBatis Plus 分页插件

6.切换数据源DruidDataSources

7.项目前端我们使用到 request 和 response拦截器,并且我们解决了跨域问题

目前该项目还有很多bug,后续再完善...

相关文章:

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

下载地址&#xff1a; 前端&#xff1a;https://download.csdn.net/download/2401_83418369/90811402 后端&#xff1a;https://download.csdn.net/download/2401_83418369/90811405 一、前端vue部分的搭建 这里直接看另一期刊的搭建Vue前端工程部分 前端vue后端ssm项目_v…...

26考研——中央处理器_指令流水线_指令流水线的基本概念 流水线的基本实现(5)

408答疑 文章目录 六、指令流水线指令流水线的基本概念流水线的基本实现流水线设计的原则流水线的逻辑结构流水线的时空图表示 八、参考资料鲍鱼科技课件26王道考研书 六、指令流水线 前面介绍的指令都是在单周期处理机中采用串行方法执行的&#xff0c;同一时刻 CPU 中只有一…...

DAY 22 复习日kaggle泰坦里克号人员生还预测

复习日 仔细回顾一下之前21天的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a; 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 kaggle泰坦里克号人员生还预测 输入&#xff1a; import pandas as pd from sklea…...

SpringCloud Gateway知识点整理和全局过滤器实现

predicate(断言)&#xff1a; 判断uri是否符合规则 • 最常用的的就是PathPredicate&#xff0c;以下列子就是只有url中有user前缀的才能被gateway识别&#xff0c;否则它不会进行路由转发 routes:- id: ***# uri: lb://starry-sky-upmsuri: http://localhost:9003/predicate…...

婴幼儿托育实训室师资协同培养模式

随着社会对婴幼儿托育服务需求的日益增长&#xff0c;培养适应市场需求的高素质托育人才成为当务之急。产教融合作为一种有效的人才培养模式&#xff0c;对于婴幼儿托育实训室建设具有重要意义&#xff0c;能够有效整合学校和企业的资源&#xff0c;为婴幼儿托育实训室人才培养…...

Gartner 《2025大数据管理规划指南》学习心得

概要 本研究旨在为数据和分析&#xff08;D&A&#xff09;技术专业人员提供2025年的数据管理规划指导&#xff0c;帮助他们应对最新数据管理趋势&#xff0c;以增强决策制定并实现卓越的业务成果。强调了持续适应数据管理实践的组织将更有能力做好人工智能&#xff08;AI&…...

理解反向Shell:隐藏在合法流量中的威胁

引言 在网络安全领域&#xff0c;​​反向Shell&#xff08;Reverse Shell&#xff09;​​ 是一种隐蔽且危险的攻击技术&#xff0c;常被渗透测试人员和攻击者用于绕过防火墙限制&#xff0c;获取对目标设备的远程控制权限。与传统的“正向Shell”&#xff08;攻击者主动连接…...

《AI大模型应知应会100篇》第55篇:大模型本地开发环境搭建

第55篇&#xff1a;大模型本地开发环境搭建 ——从零开始构建你的AI炼金炉 &#x1f4cc; 摘要 在人工智能尤其是大模型&#xff08;LLM&#xff09;领域&#xff0c;一个高效、稳定、可扩展的本地开发环境是每位开发者的第一块基石。本文将手把手带你完成从硬件选型到软件配…...

AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年5月11日第74弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀6-8个和值&#xff0c;可以做到100-300注左右。 (1)定…...

Docker:安装配置教程(最新版本)

文章目录 一、前言二、具体操作2.1 卸载 Docker (可选)2.2 重新安装&#xff08;使用清华大学镜像&#xff09;2.3 配置轩辕镜像加速2.4 Docker 基本命名2.5 测试是否成功 三、结语 一、前言 Docker 是一种容器化技术&#xff0c;在软件开发和部署中得到广泛的应用&#xff0c…...

数据结构【二叉树的遍历实现】

&#x1f4d8;考研数据结构基础&#xff1a;二叉树的存储、遍历与队列辅助实现详 在数据结构的学习中&#xff0c;二叉树作为一种结构清晰、应用广泛的树形结构&#xff0c;是考研计算机专业课中重点内容之一。本文将以实际代码为基础&#xff0c;介绍二叉树的存储结构、遍历方…...

稳态电路和瞬态电路

一、概述 稳态电路是指电路在长时间运行后达到的一种稳定状态&#xff1b; 瞬态电路是指电路在切换或者初始化节点经历过渡的过程。 在电路分析中&#xff0c;稳态和瞬态是动态电路的两个阶段。在电路中&#xff0c;如果有电感或者电容时&#xff0c; 他们的电压和电流不能瞬间…...

spark运行架构及核心组件介绍

目录 1. Spark 的运行架构1.1 Driver1.2 Executor1.3 Cluster Manager1.4 工作流程 2. Spark 的核心组件2.1 Spark Core2.2 Spark SQL2.3 Spark Streaming2.4 MLlib2.5 GraphX 3. Spark 架构图4. Spark 的优势4.1 高性能4.2 易用性4.3 扩展性4.4 容错性 5. 总结 1. Spark 的运行…...

Linux服务器常用运维工具/命令

常用工具/命令 1、查看内存使用 free -m上述命令用于显示系统中内存的使用情况&#xff0c;并将内存使用量以兆字节&#xff08;MB&#xff09;为单位显示。这个命令在 Linux 和类 Unix 系统上非常常见&#xff0c;是监视系统内存的一个简单而有用的工具。 具体而言&#xf…...

KaiwuDB 2.0:为 AIoT 而生,融合时序、关系与 AI 的未来数据库

目录: 引言:AIoT 数据洪流下的数据库“窘境”KaiwuDB 2.0:为 AIoT “量身定制”的智能数据基座核心利器:多模融合 + 原生 AI,解锁数据新范式不止于云:KaiwuDB Lite 轻装上阵边缘计算硬核实力:AIoT 场景下的显著优势技术基因:融合创新,构筑未来数据架构应用蓝图:深耕 A…...

Python打卡训练营Day22

浙大疏锦行 DAY 22 复习日 复习日 仔细回顾一下之前21天的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a; 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 kaggle 一、Kaggle 核心功能学习参考 注册与基础设置…...

Oracle — 内置函数

介绍 Oracle内置函数是数据库中预定义的编程工具&#xff0c;用于简化数据处理与计算逻辑。这些函数分为单行函数和聚合函数两大类。单行函数针对每条数据独立运算&#xff0c;例如LOWER函数转换文本为小写&#xff0c;ROUND实现数值四舍五入&#xff0c;TO_CHAR格式化日期输出…...

Kubernetes基础(三十二):Worker节点启动全解析

Worker节点是Kubernetes集群的"肌肉"&#xff0c;负责实际运行业务负载。本文将深入剖析Worker节点的完整启动流程&#xff0c;并揭秘生产环境中的关键优化点。 一、启动流程全景图 二、核心启动阶段详解 1. 系统初始化&#xff08;0-30秒&#xff09; 关键任务&a…...

“爱生活”小项目问题总结

目录 爱生活小程序 1.用户登录和注册模块遇到的问题 1.1在使用密码加密时&#xff0c;注册新用户&#xff0c;客户端响应401的问题 原因&#xff1a; 正确操作&#xff1a; 1.2在设置密码加密后&#xff0c;发送post登录请求&#xff0c;服务器出现报错java.lang.reflect.…...

实战项目5(08)

目录 任务场景一 【r1配置】 【r2配置】 【r3配置】 ​​​​​​​任务场景二 【r1配置】 【r2配置】 ​​​​​​​任务场景一 按照下图完成网络拓扑搭建和配置 任务要求&#xff1a; 通过在路由器R1、R2和R3上配置静态路由&#xff0c;实现网络中各终端PC能够正常…...

LeetCode 1550.存在连续三个奇数的数组:遍历

【LetMeFly】1550.存在连续三个奇数的数组&#xff1a;遍历 力扣题目链接&#xff1a;https://leetcode.cn/problems/three-consecutive-odds/ 给你一个整数数组 arr&#xff0c;请你判断数组中是否存在连续三个元素都是奇数的情况&#xff1a;如果存在&#xff0c;请返回 tr…...

大模型在肾肿瘤诊疗全流程预测及方案制定中的应用研究

目录 一、引言 1.1 研究背景与意义 1.2 研究目的 1.3 研究创新点 1.4 研究方法与数据来源 二、肾肿瘤概述与大模型技术 2.1 肾肿瘤相关知识 2.1.1 定义、分类及症状 2.1.2 发病机制与影响因素 2.1.3 治疗现状与挑战 2.2 大模型技术原理及医疗应用现状 2.2.1 大模型…...

5月11号.

导入Maven项目: Maven依赖管理: 生命周期: 测试: 断言: Junit常见注解:...

数据库基础概述

一、基础概述 1.数据库 &#xff08;1&#xff09;概述 数据库就是存储数据的仓库&#xff0c;其本质是一个文件系统&#xff0c;按照特定的格式将数据存储起来&#xff0c;用户可以对数据库中的数据进行增加&#xff0c;修改&#xff0c;删除及查询操作使用数据库可以高效的…...

Hibernate 性能优化:告别慢查询,提升数据库访问性能

Hibernate 性能优化&#xff1a;告别慢查询&#xff0c;提升数据库访问性能 Hibernate 作为一款流行的 ORM 框架&#xff0c;极大地简化了 Java 应用程序与数据库之间的交互&#xff0c;但如果不进行合理优化&#xff0c;性能瓶颈在高并发场景下就会暴露无遗。本文将深入探讨 …...

【JavaWeb+后端常用部件】

回顾内容看&#xff1a; 一、获取请求参数的方法 参考&#xff1a;[JavaWeb]——获取请求参数的方式(全面&#xff01;&#xff01;&#xff01;)_java 获取请求参数-CSDN博客 Json格式的Body加备注RequestBody{id}动态路径加备注PathVariableid?&name?直接接收就好 i…...

Playwright 简介

Playwright 简介 说明:本教程基于 @playwright/test@1.51.1 版本编写,内容和目录结构与该版本官方推荐保持一致。 适合人群与学习路径 适合谁? 想入门自动化测试的测试工程师需要跨浏览器、移动端自动化的开发者希望提升测试效率、减少维护成本的团队学习建议 跟着文档动手实…...

# 2-STM32-复位和时钟控制RCC

STM32-复位和时钟控制RCC 2-STM32-复位和时钟控制RCC摘要说明本文参考资料如下&#xff1a; 一、STM32最小系统回顾STM32F103C8T6核心板原理图 二、复位三、时钟3.1 时钟树3.2 STM32启动过程3.2 SystemInit()函数3.2.1 SystemInit()第1句&#xff1a;3.2.2 SystemInit()第2句&a…...

idea中的vcs不见了,如何解决

按如下顺序依次找 filesettingsversion controldirectory mappings点击号vcs 改为Subversion 省流&#xff1a;看如下图...

元数据分类

元数据&#xff08;Metadata&#xff09;是描述数据的数据&#xff0c;通常分为 业务元数据、技术元数据 和 操作元数据。这三类元数据从不同维度对数据进行描述和管理&#xff0c;以下是它们的定义、作用和示例&#xff1a; 1. 业务元数据&#xff08;Business Metadata&#…...

【C语言】(9)—指针3

文章目录 一、字符指针的深入理解二、数组指针详解三、二维数组传参的本质四、函数指针及其应用五、函数指针数组与转移表 一、字符指针的深入理解 1.1 字符指针的基本使用 字符指针(char*)是指向字符类型数据的指针&#xff0c;它有两种常见的使用方式&#xff1a; // 方式一…...

拍电影为什么常用绿幕?认识色度键控(Chroma Key)技术

许多电影拍摄使用绿幕技术,其核心原因在于它通过色度键控(Chroma Key)技术实现背景替换,从而为创作提供高度灵活性、成本效益和视觉效果的可控性。以下从技术原理、应用场景、优势及与其他技术的对比等方面展开分析: 一、绿幕技术的基本原理 绿幕技术的核心是色度键控(C…...

【iOS】Tagged Pointer

【iOS】Tagged Pointer 文章目录 【iOS】Tagged Pointer前言认识Tagged Pointer使用案例结构isa指针经典面试题 前言 在之前的学习中笔者在字符串章节简单了解过这个Tagged Pointer后面笔者就没在多了解这部分内容,今天决定比较系统的学习一下有关于这部分内容的知识. 认识Tagg…...

17.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--微服务基础工具与技术--loki

在微服务中&#xff0c;日志是非常重要的组成部分。它不仅可以帮助我们排查问题&#xff0c;还可以帮助我们分析系统的性能和使用情况。 一、loki简介 loki是一个开源的日志聚合系统&#xff0c;它可以帮助我们高效地收集、存储和分析日志数据。loki的设计理念是“简单、快速…...

OpenWrt开发第8篇:树莓派开发板做无线接入点

文/指尖动听知识库-谷谷 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:Openwrt开发-基于Raspberry Pi 4B开发板 树莓派开发板作为无线接入点的时候,可以通过电脑和手机打开WiFi功能搜索到相应打开的WiFi; 1 通过Web操作界面开启wifi 1...

电源架构与太阳能充电器电路设计分析

一、电源架构基本工作原理分析 #mermaid-svg-mEaBEAY5xdCMN9Uy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-mEaBEAY5xdCMN9Uy .error-icon{fill:#552222;}#mermaid-svg-mEaBEAY5xdCMN9Uy .error-text{fill:#5522…...

英语句型结构

句型类型结构示例示例解释应用场合简单句主谓&#xff08;SV&#xff09;The bird flies.“The bird” 是主语&#xff0c;“flies” 是不及物动词作谓语&#xff0c;描述鸟 “飞” 的动作。描述事物基本行为&#xff0c;如动物习性、自然现象等。主谓宾&#xff08;SVO&#x…...

什么是卷积神经网络

卷积神经网络(CNN)的全面解析 卷积神经网络(Convolutional Neural Network, CNN)是深度学习领域最成功的模型之一,尤其在图像处理和模式识别任务中表现卓越。以下从基本结构、核心组件、发展历程、应用场景、数学基础、训练方法及优缺点等方面展开详述。 一、基本定义与核…...

操作系统: 第三章节 :中断和处理机调度

一:中断与中断系统 -1:中断的概念: 在程序运行过程中出现某紧急事件&#xff0c;必须中止当前正在运行的程序&#xff0c;转去处理这个事件&#xff0c;然后再恢复原来运行的程序&#xff0c;这一过程称为中断. -2:中断装置(硬件): 发现并相应中断的硬件结构: 工作: -----…...

嵌入式硬件篇---IIC

文章目录 前言1. IC协议基础1.1 物理层特性两根信号线SCLSDA支持多主多从 标准模式电平 1.2 通信流程起始条件&#xff08;Start Condition&#xff09;从机地址&#xff08;Slave Address&#xff09;应答&#xff08;ACK/NACK&#xff09;数据传输&#xff1a;停止条件&#…...

SAP学习笔记 - 开发08 - Eclipse连接到 BTP Cockpit实例

有关BTP&#xff0c;之前学了一点儿&#xff0c;今天继续学习。 SAP学习笔记 - 开发02 - BTP实操流程&#xff08;账号注册&#xff0c;BTP控制台&#xff0c;BTP集成开发环境搭建&#xff09;_sap btp开发-CSDN博客 如何在Eclipse中连接BTP Cockpit开发环境实例。 1&#xf…...

安装typescript时,npm install -g typescript报错

删除C:\Users\用户\下的.npmrc文件,如果你的没有&#xff0c;看是不是因为将隐藏的项目勾选上了&#xff0c;然后去掉勾选。 重新输入...

支持selenium的chrome driver更新到136.0.7103.92

最近chrome释放新版本&#xff1a;136.0.7103.92 如果运行selenium自动化测试出现以下问题&#xff0c;是需要升级chromedriver才可以解决的。 selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only su…...

Java在人工智能中的应用:机器学习与深度学习技术探讨

根据您提供的知识库内容&#xff0c;我发现其中主要涉及机器学习和深度学习的内容&#xff0c;而您的文章是关于Java面试技术的。两者的主题并不直接相关&#xff0c;因此无法直接使用知识库中的信息来润色您的文章。 如果您希望将机器学习和深度学习的内容融入文章中&#xf…...

C++23 新特性:深入解析 std::views::join_with(P2441R2)

文章目录 std::views::join_with 基本用法处理字符串集合std::views::join_with 与其他视图的结合使用总结 随着C23标准的逐步推进&#xff0c;我们迎来了许多令人兴奋的新特性&#xff0c;其中之一就是 std::views::join_with。这个新特性是C23中引入的视图适配器&#xff0c…...

【工作记录】crmeb后端项目打开、运行

1、下载代码 1&#xff09;安装git 不再详述 2&#xff09;git拉代码 项目地址如下&#xff0c;在vscode-分支中拉代码 # 克隆项目 git clone https://gitee.com/ZhongBangKeJi/crmeb_java/ 截图如下是已经成功拉下来 注意安装对应版本 2、maven配置 安装配置见&#x…...

前端浏览器判断设备类型的方法

前端浏览器判断设备类型的方法 在前端开发中&#xff0c;判断设备类型&#xff08;如手机、平板、桌面电脑&#xff09;有多种方法&#xff0c;以下是常用的几种方式&#xff1a; 1. 使用 User Agent 检测 通过 navigator.userAgent 获取用户代理字符串进行判断&#xff1a;…...

python 新闻 api + react js 客户端。

1. 起因&#xff0c; 目的: 前面写了几个爬虫。 那么这些数据怎么使用。使用 api &#xff0c; 看看到底有哪些新闻。感受&#xff1a;最初只是一个想法&#xff0c;然而实现的过程中却很枯燥乏味&#xff0c; 甚至怀疑为什么要做这个事情. 2. 先看效果 效果就是能行。 3.…...

Vivado中可新建的工程类型解析

以下是Vivado中可新建的工程类型解析&#xff0c;按用途和场景分类说明&#xff1a; 1. RTL Project&#xff08;RTL工程&#xff09; 用途&#xff1a;从零开始基于RTL代码&#xff08;Verilog/VHDL&#xff09;设计FPGA逻辑&#xff0c;覆盖完整开发流程。适用阶段&#xff…...

TypeScript 中的泛型工具详解

TypeScript 提供了一系列强大的泛型工具类型&#xff0c;可以帮助我们更灵活地操作和转换类型。以下是主要的泛型工具类型及其用法&#xff1a; 1. 基础工具类型 1.1. Partial<T> 将类型 T 的所有属性变为可选。 interface User {name: string;age: number; }type Pa…...