springboot+vite 商品管理
SpringBoot + Vue3 +MySql5.7 +JDK8
一、 SpringBoot项目搭建
1 SpringBoot概述
1.1 SpringBoot 概念
SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻 辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度 上缩短了项目周期。2014 年4 月,Spring Boot 1.0.0 发布。Spring的顶级项目之一(https://spring.io)。
1.2 Spring缺点
1.2.1 配置繁琐
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多 XML配置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。 Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。 所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所 以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但它要求的回报也不少。
1.2.2 依赖繁琐
项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导 入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
1.3 SpringBoot 功能
1.3.1 自动配置
Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定 Spring配置应该用哪个,不该用哪个。该过程是SpringBoot自动完成的。
1.3.2 起步依赖
起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖 ,这些东西加在一起即支持某项功能。 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
1.3.3 辅助功能
提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用Spring 的方式。
2 Springboot快速入门
2.1 案例需求
搭建SpringBoot工程,定义HelloWorldController.hello()方法,返回”Hello SpringBoot!”。
2.2 案例实现步骤
1)创建项目
2)定义Controller
3)启动测试
2.2.1 创建Maven项目
·
配置URL
https://start.aliyun.com
配置Maven仓库
2.2.2 新建HelloController测试
HelloController.java
@RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "Hello SpringBoot"; } }
启动测试
浏览器测试
3 数据库
3.1 新建数据库
3.2 新建表
use hddata; CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID,自增长', username VARCHAR(50) NOT NULL COMMENT '用户名', password VARCHAR(255) NOT NULL COMMENT '用户密码', name VARCHAR(100) NOT NULL COMMENT '姓名' ) COMMENT='用户信息表'; CREATE TABLE product ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '商品ID,自增长', number VARCHAR(50) NOT NULL COMMENT '商品编号', name VARCHAR(100) NOT NULL COMMENT '商品名称', brand INT NOT NULL COMMENT '商品品牌' ) COMMENT='商品信息表';
4 项目实战
4.1 引入相关依赖
<!-- 引入MyBatis plus依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> </dependency> <!--mysql驱动依赖--> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency> <!--hutool工具类--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version> </dependency> <!--validation依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>3.1.0</version> </dependency> <!--pageHelper 分页插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.7</version> </dependency>
4.2 分层建包
User类
@Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type = IdType.AUTO) private int id; // 用户ID,自增长 private String username; // 用户名 private String password; // 用户密码 private String name; // 姓名 }
4.3 数据库配置
#数据库配置 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hddata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC username: root password: fp #mybatis-plus配置 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath*:/mybatis/*.xml type-aliases-package: com.hwadee.userproject.pojo
4.4 创建用户数据层
UserMapper
public interface UserMapper extends BaseMapper<User> { }
配置mapper包扫描
@SpringBootApplication @MapperScan("com.hwadee.userproject.mapper") public class UserProjectApplication { public static void main(String[] args) { SpringApplication.run(UserProjectApplication.class, args); } }
mybatis-plus测试
@SpringBootTest class UserProjectApplicationTests { @Autowired UserMapper userMapper; //新增用户 @Test void contextLoads() { User user = new User(); user.setUsername("admin"); user.setPassword(DigestUtil.md5Hex("123456")); user.setName("管理员"); userMapper.insert(user); } //查询所有用户 @Test void contextLoads1() { List<User> users = userMapper.selectList(null); System.out.println("====用户数据===="); users.forEach(user -> System.out.println(user)); } }
4.5 创建前后端交互对象
DataResult
public class DataResult<T> implements Serializable { private static final long serialVersionUID = 1L; private boolean success = true; private String message = "操作成功!"; private Integer statusCode = 200; private T data; private long timestamp = System.currentTimeMillis(); public DataResult() { } public DataResult(Boolean success, Integer code, String msg, T data) { this.success = success; this.statusCode = code; this.message = msg; this.data = data; } //返回成功 public static DataResult success() { return new DataResult(true,200, "操作成功!", null); } //返回失败 500 public static DataResult error(String message) { return new DataResult(false,HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null); } //返回成功并携带数据 public static <T> DataResult<T> success(T data) { return new DataResult<T>(true,200, "操作成功!", data); } public boolean getSuccess() { return this.success; } public void setSuccess(boolean success) { this.success = success; } public String getMessage() { return this.message; } public void setMessage(String message) { this.message = message; } public Integer getStatusCode() { return this.statusCode; } public void setStatusCode(Integer statusCode) { this.statusCode = statusCode; } public T getData() { return this.data; } public void setData(T data) { this.data = data; } public long getTimestamp() { return this.timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } }
4.6 数据校验
User
@Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type = IdType.AUTO) private int id; // 用户ID,自增长 @NotNull(message = "用户名不能为空") @Pattern(regexp = "^[\\x00-\\x7F]+$", message = "用户名不能包含汉字") @Size(min = 3, message = "用户名长度必须大于2个字符") private String username; // 用户名 @NotNull(message = "密码不能为空") @Pattern(regexp = "^[\\x00-\\x7F]+$", message = "密码不能包含汉字") @Size(min = 3, message = "密码长度必须大于2个字符") private String password; // 用户密码 private String name; // 姓名 }
4.7 全局控制异常
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public DataResult handleException(Exception e){ e.printStackTrace(); return DataResult.error(StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "操作失败"); } }
4.8 用户注册
开启事务
@SpringBootApplication @MapperScan("com.hwadee.userproject.mapper") @EnableTransactionManagement//开启事务管理 public class UserProjectApplication { public static void main(String[] args) { SpringApplication.run(UserProjectApplication.class, args); } }
@RestController @RequestMapping("/user") public class UserController { @Resource private UserMapper userMapper; @RequestMapping("/register") @Transactional(rollbackFor = Exception.class) //事务控制 public DataResult register(@Validated @RequestBody User user){ if(!StringUtils.hasLength(user.getName())){ return DataResult.error("姓名不能为空"); } QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username",user.getUsername()); User user1 = userMapper.selectOne(queryWrapper); if (Objects.isNull(user1)){ user.setPassword(DigestUtil.md5Hex(user.getPassword())); userMapper.insert(user); //int i = 1/0; //测试事务 return DataResult.success("注册成功"); }else { return DataResult.error("用户名已存在"); } } }
PostMan测试
4.9 用户登录
/** * 用户登录 * @param user * @return */ @PostMapping("/login") public DataResult login(@Validated @RequestBody User user) { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("username", user.getUsername()); //查询用户 User user1 = userMapper.selectOne(wrapper); if (Objects.nonNull(user1)) { //用户存在,校验密码 if (user1.getPassword().equals(DigestUtil.md5Hex(user.getPassword()))) { return DataResult.success("登录成功"); } return DataResult.error("密码错误"); } else { return DataResult.error("用户名错误"); } }
测试
4.9 配置跨域
CorsConfig
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 所有接口 .allowCredentials(true) // 是否发送 Cookie .allowedOriginPatterns("*") // 允许的源(Spring 5.3 及以上版本支持通配符) .allowedMethods("GET", "POST", "PUT", "DELETE") // 支持的方法 .allowedHeaders("*") // 允许的头部信息 .exposedHeaders("Authorization", "Content-Type"); // 暴露的头部信息 } }
二、Vue项目搭建
必须先安装node
软件安装:nodejs16
https://nodejs.org/download/release/v16.20.0/
1 创建项目
1.1 安装vite环境
cmd进去项目目录,依次执行以下命令
#配置新淘宝镜像(防止出现下载缓慢) npm config set registry https://registry.npmmirror.com #查看当前的 npm 镜像地址 npm config get registry #安装vite npm init vite@latest #Package name 就是项目的包名,它用于唯一标识你的项目,在项目的配置文件 package.json 中使用。
1.2 启动项目
# 安装依赖 npm i #启动项目 npm run dev
1.3 项目结构介绍
node_modules:
通过 npm install 下载安装的项目依赖包
public:
存放静态资源公共资源,不会被压缩合并
—3DModel:存放.glb3D模型
—favicon.ico:网站图标
—index.html:首页入口.html文件
src:
项目开发主要文件夹
—api
—assets:静态文件,存放图片
—components:存放组件
—store:与vuex相关
—styles:存放样式
—utils:工具类
—views:界面组件
—App.vue:根组件
—main.js:入口文件
—router.js:存放路由,实现界面跳转
.gitignore:
用来配置那些文件不归git管理
package.json:
项目配置和包管理文件(项目依赖和技术)
package-lock.json :
锁定依赖的版本信息,确保不同的开发者在不同的时间或环境中使用相同的版本。
README.md:
说明文档,主要看项目运行的命令
vue.config.js:
项目配置信息:跨域proxy代理
2 引入相关配置
配置@全局路径设置
vite.config.js
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' //记得引入 import { fileURLToPath, URL } from 'node:url' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } })
2.1 引入静态文件
main.js
//注释默认样式 //import './style.css' //引入公共样式 import './assets/base.css'
2.2 引入Element-plus
#安装 npm install element-plus --save
main.js
//引入ElementPlus import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' //在 mount 之前调用 use 方法 createApp(App).use(ElementPlus).mount('#app')
在Hellowold.vue中测试是否引入成功
<template> <div style="margin-top: 20px"> <el-button>Default</el-button> <el-button type="primary">Primary</el-button> <el-button type="success">Success</el-button> <el-button type="info">Info</el-button> <el-button type="warning">Warning</el-button> <el-button type="danger">Danger</el-button> </div> </template> <script setup lang='js'> </script> <style lang='scss' scoped> </style>
2.3 引入router
#安装 npm install vue-router@latest
创建views/HomeView.vue
<template> <div style="margin-top: 20px"> Home </div> </template> <script setup lang='js'> </script> <style lang='scss' scoped> </style>
创建router/index.js
index.js
import { createRouter,createWebHistory } from 'vue-router' //导入组件 import Home from '@/views/home/HomeView.vue' //定义路由关系 const routes = [ { path: '/home', name: 'home', component: Home } ] //创建路由器 const router = createRouter({ history: createWebHistory(), routes:routes }) //导出路由 export default router
main.js
// @/router 如果不直接写后面的路径,默认找index.js import router from '@/router/index.js' //在 mount 之前调用 use 方法 createApp(App).use(router).use(ElementPlus).mount('#app')
App.vue
<template> <!-- 全局配置组件 --> <el-config-provider :locale="zhCn"> <RouterView /> </el-config-provider> </template> <script setup> import {ElConfigProvider} from "element-plus"; import {zhCn} from "element-plus/es/locale/index"; </script>
测试路由
2.4 安装axios
npm install axios -S
创建utils/request.js
import axios from 'axios'; const URL = "http://localhost:8080"; // create an axios instance const service = axios.create({ baseURL: URL, // url = base url + request url timeout: 10000, // request timeout withCredentials: true, crossDomain: true }) export default service
创建后端api/getData.js
import request from "@/utils/request"; /** * 用户登录的api * @param data */ export const doLogin=(data)=>{ return request({ url:'user/login', //请求url method :'post', //请求方式 data //请求参数 }) }
3 登录页面
新建/views/login/LoginView.vue
<template> <div class="login-container"> <el-card class="login-card"> <div class="login-header"> <h3 class="login-title">欢迎登录</h3> <p class="login-subtitle">校园管理系统</p> </div> <el-form ref="loginFormRule" :model="loginForm" :rules="rules" label-width="auto" class="loin-form" > <el-form-item label="用户名" prop="username"> <el-input v-model="loginForm.username" autocomplete="off" placeholder="请输入用户名" /> </el-form-item> <el-form-item label="密码" prop="password"> <el-input v-model="loginForm.password" type="password" autocomplete="off" placeholder="请输入密码"/> </el-form-item> <el-form-item> <el-button class="login-button" type="primary" @click="submitForm()"> 登录 </el-button> </el-form-item> </el-form> </el-card> </div> </template> <script setup> import {ref} from "vue"; import {ElMessage} from "element-plus"; import {doLogin} from "@/api/getData.js"; import router from "@/router/index.js"; /** * 表单绑定的数据 * @type {Ref<UnwrapRef<{password: string, username: string}>>} */ const loginForm = ref({ username:'', password:'', }) const loginFormRule = ref(null); /** * 提交 */ const submitForm =()=>{ //提交前验证 loginFormRule.value.validate((valid)=>{ if(valid){ login(); }else{ ElMessage.error("请输入用户名或密码") } }) //跳转到首页 } /** * 登录方法 */ const login = ()=>{ doLogin(loginForm.value).then(({data})=>{ if(data.statusCode == 200){ router.push("/home") }else{ ElMessage.error(data.message) } }) } /** * 验证表单规则 * @type {Ref<any>} */ const rules = ref({ username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 2, message: '用户名长度最小为2个字符', trigger: 'blur' }, { pattern: /^[^\u4e00-\u9fa5]+$/, message: '用户名不能包含汉字', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' }, { min: 2, message: '密码长度最小为2个字符', trigger: 'blur' }, { pattern: /^[^\u4e00-\u9fa5]+$/, message: '密码不能包含汉字', trigger: 'blur' } ] }); </script> <style scoped> .login-container{ display: flex; justify-content: center; align-items: center; height: 100vh; background: linear-gradient(to right, #00b2ff, #00b2ff, #1550a8); } .login-card{ width: 600px; padding: 40px; text-align: center; border-radius: 16px; box-shadow: 0 4px 8px rgb(0,0,0,0.1); } .login-header{ margin-bottom: 40px; } .login-title{ font-size: 30px; font-weight: bold; color: #333333; margin-bottom: 10px; letter-spacing: 10px; } .login-subtitle{ font-size: 25px; color: #666666; letter-spacing: 20px; } .loin-form{ width: 100%; } .login-button{ width: 100%; font-size: 16px; } </style>
三、商品的增删改查
1 新建表
-- 使用自己的数据库 use hddata; CREATE TABLE product ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '商品ID,自增长', number VARCHAR(50) NOT NULL COMMENT '商品编号', name VARCHAR(100) NOT NULL COMMENT '商品名称', brand VARCHAR(50) NOT NULL COMMENT '商品品牌' ) COMMENT='商品信息表';
2 后端代码
2.1 新建实体类
Product
@Data @AllArgsConstructor @NoArgsConstructor public class Product { @TableId(type = IdType.AUTO) private int id; @NotEmpty(message = "编号不能为空") private String number; @NotEmpty(message = "名称不能为空") private String name; @NotEmpty(message = "品牌不能为空") private String brand; }
2.2 新建数据层接口
ProductMapper
public interface ProductMapper extends BaseMapper<Product> { }
2.3 新建控制层
商品查询
ProductController
@RestController @RequestMapping("/product") public class ProductController { @Resource private ProductMapper productMapper; /** * 查询所有商品 */ @RequestMapping("/list") public DataResult list(@RequestParam(required = false) String name) { QueryWrapper<Product> queryWrapper = new QueryWrapper<>(); if (StringUtils.hasLength(name)) { queryWrapper.like("name", name); } List<Product> brands = productMapper.selectList(queryWrapper); return DataResult.success(brands); } }
浏览器测试
商品添加
/** * 添加商品 */ @RequestMapping("/add") @Transactional public DataResult add(@Validated @RequestBody Product product) { productMapper.insert(product); return DataResult.success(); }
测试
编辑商品
先通过id回显数据
/** * 通过主键查找 * @param id * @return */ @RequestMapping("/getById") public DataResult getById(@RequestParam String id){ Product product = productMapper.selectById(id); return DataResult.success(product); }
测试
编辑商品
/** * 编辑商品 */ @RequestMapping("/edit") @Transactional public DataResult edit(@Validated @RequestBody Product product) { if(product.getId() == 0){ return DataResult.error("id不能为空"); } productMapper.updateById(product); return DataResult.success(); }
测试
删除商品
/** * 删除商品 * @param id * @return */ @RequestMapping("/delete") @Transactional public DataResult delete(@RequestParam String id){ if(!StringUtils.hasLength(id)){ return DataResult.error("id不能为空"); } productMapper.deleteById(id); return DataResult.success(); }
3 前端代码
3.1 商品列表
新建/views/product/ProductView.vue
配置路由跳转
import Product from '@/views/product/ProductView.vue' //定义路由关系 const routes = [ { path: '/', name: 'login', component: Login }, { path: '/home', name: 'home', component: Home }, { path: '/product', name: 'product', component: Product } ]
修改登录后路由跳转到商品界面
点击登录测试
ProductView.vue
<template> <el-card > <template #header> <div class="card-header"> <span>商品管理</span> <el-button type="primary" @click="visibleDrawer=true ;drawerTile='新增商品'">新增商品</el-button> </div> </template> <!-- 搜索表单--> <el-form :inline="true" :model="searchForm" class="demo-form-inline"> <el-form-item label="名称"> <el-input v-model="searchProductName" placeholder="请输入商品名称" clearable /> </el-form-item> <el-form-item> <el-button type="primary" @click="productList">搜索</el-button> </el-form-item> </el-form> <!-- 商品显示列表--> <el-table :data="products" style="width: 100%"> <el-table-column prop="number" label="编号" width="200" /> <el-table-column prop="name" label="名称" width="200" /> <el-table-column prop="brand" label="品牌" width="200" /> <!-- <el-table-column fixed="right" label="操作" min-width="200"> <template #default="{row}"> <el-button type="primary" size="small" @click="handleEdit(row)"> 编辑 </el-button> <el-button type="danger" size="small" @click="handleDelete(row)"> 删除</el-button> </template> </el-table-column> --> </el-table> </el-card> </template> <script setup lang='js'> import {ref} from "vue"; import {getProductByNameList} from "@/api/getData.js"; import {ElMessage, ElMessageBox} from "element-plus"; /** * 定义搜索表单数据 * @type {Ref<UnwrapRef<{}>>} */ const searchForm = ref({}) /** * 定义搜索字段 * @type {Ref<any>} */ const searchProductName = ref(''); //列表数据 const products = ref([]) /** * 定义查询商品的方法 */ const productList = ()=>{ getProductByNameList(searchProductName.value).then(({data})=>{ if(data.statusCode==200){ products.value = data.data } }) } //查询数据 productList() </script> <style scoped> .card-header{ display: flex; justify-content: space-between; align-items: center; } </style>
添加后端接口
getData.js
/** * 查询商品列表的api * @param data */ export const getProductByNameList=(name)=>{ return request({ url:'product/list?name='+ name, //请求url method :'post' //请求方式 }) }
测试
3.2 新增商品
<!-- 抽屉样式的编辑框--> <el-drawer v-model="visibleDrawer" :title="drawerTile" :direction="rt1" size="30%" > <el-form :model="productModel" label-width="auto" style="max-width: 600px"> <el-form-item label="编号"> <el-input v-model="productModel.number" placeholder="请输入编号" /> </el-form-item> <el-form-item label="名称"> <el-input v-model="productModel.name" placeholder="请输入名称" /> </el-form-item> <el-form-item label="品牌"> <el-input v-model="productModel.brand" placeholder="请输入品牌" /> </el-form-item> <el-form-item> <el-button type="primary" @click="drawerTile == '新增商品' ? doAddProduct() : doUpdateProduct()">提交</el-button> </el-form-item> </el-form> </el-drawer>
定义相关数据变量
//编辑框数据 const visibleDrawer = ref(false) //显示或者隐藏 const drawerTile = ref('') //新增或者编辑 const productModel = ref({ id: 0, number: '', name: '', brand: '' }) const clearData = ()=>{ productModel.value = { id: 0, number: '', name: '', brand: '' } } //新增商品 const doAddProduct= ()=>{ addProduct(productModel.value).then(({data})=>{ if(data.statusCode==200){ ElMessage.success("添加成功") } clearData() visibleDrawer.value=false; productList(); }) } //编辑商品 const doUpdateProduct = () => { }
<el-button type="primary" @click=" visibleDrawer = true;drawerTile = '新增商品';">新增商品</el-button>
添加后端接口
/** * 添加商品 * @param data */ export const addProduct=(data)=>{ return request({ url:'product/add' ,//请求url method :'post', //请求方式 data }) }
测试代码
3.2 编辑商品
<el-table-column fixed="right" label="操作" min-width="200"> <template #default="{row}"> <el-button type="primary" size="small" @click="handleEdit(row)"> 编辑 </el-button> <el-button type="danger" size="small" @click="handleDelete(row)"> 删除</el-button> </template> </el-table-column>
添加编辑事件
//编辑商品 const doUpdateProduct = () => { updateProduct(productModel.value).then((data)=>{ if(data.status==200){ ElMessage.success("编辑成功") } clearData() visibleDrawer.value=false; productList(); }) } /** * 打开编辑 */ const handleEdit = (row)=>{ visibleDrawer.value=true drawerTile.value="编辑商品" // 数据赋值给 model productModel.value = row; productModel.value.id= row.id }
添加后端接口
/** * 编辑商品 */ export const updateProduct=(data)=>{ return request({ url:'product/edit' ,//请求url method :'post', //请求方式 data }) }
测试
3.3 删除商品
/** * 删除方法 */ const handleDelete = (row)=>{ ElMessageBox.confirm( '您确定删除这条数据么', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', } ) .then(() => { deleteProduct(row.id).then(({data})=>{ if(data.statusCode==200){ productList(); ElMessage({ type: 'success', message: '删除成功', }) } }) }) .catch(() => { ElMessage({ type: 'info', message: '取消删除', }) }) }
添加后端接口
/** * 删除商品 */ export const deleteProduct=(id)=>{ return request({ url:'product/delete?id='+id, //请求url method :'post', //请求方式 }) }
测试
3.4 ProductView.vue 完整代码
<template> <el-card> <template #header> <div class="card-header"> <span>商品管理</span> <el-button type="primary" @click=" visibleDrawer = true;drawerTile = '新增商品';">新增商品</el-button> </div> </template> <!-- 搜索表单--> <el-form :inline="true" :model="searchForm" class="demo-form-inline"> <el-form-item label="名称"> <el-input v-model="searchProductName" placeholder="请输入商品名称" clearable /> </el-form-item> <el-form-item> <el-button type="primary" @click="productList">搜索</el-button> </el-form-item> </el-form> <!-- 商品显示列表--> <el-table :data="products" style="width: 100%"> <el-table-column prop="number" label="编号" width="200" /> <el-table-column prop="name" label="名称" width="200" /> <el-table-column prop="brand" label="品牌" width="200" /> <el-table-column fixed="right" label="操作" min-width="200"> <template #default="{row}"> <el-button type="primary" size="small" @click="handleEdit(row)"> 编辑 </el-button> <el-button type="danger" size="small" @click="handleDelete(row)"> 删除</el-button> </template> </el-table-column> </el-table> </el-card> <!-- 抽屉样式的编辑框--> <el-drawer v-model="visibleDrawer" :title="drawerTile" :direction="rt1" size="30%" > <el-form :model="productModel" label-width="auto" style="max-width: 600px"> <el-form-item label="编号"> <el-input v-model="productModel.number" placeholder="请输入编号" /> </el-form-item> <el-form-item label="名称"> <el-input v-model="productModel.name" placeholder="请输入名称" /> </el-form-item> <el-form-item label="品牌"> <el-input v-model="productModel.brand" placeholder="请输入品牌" /> </el-form-item> <el-form-item> <el-button type="primary" @click="drawerTile == '新增商品' ? doAddProduct() : doUpdateProduct()">提交</el-button> </el-form-item> </el-form> </el-drawer> </template> <script setup lang="js"> import {ref} from "vue"; import {getProductByNameList,addProduct,updateProduct,deleteProduct} from "@/api/getData.js"; import {ElMessage, ElMessageBox} from "element-plus"; /** * 定义搜索表单数据 * @type {Ref<UnwrapRef<{}>>} */ const searchForm = ref({}) /** * 定义搜索字段 * @type {Ref<any>} */ const searchProductName = ref(''); //列表数据 const products = ref([]) /** * 定义查询商品的方法 */ const productList = ()=>{ getProductByNameList(searchProductName.value).then(({data})=>{ if(data.statusCode==200){ products.value = data.data } }) } //查询数据 productList() //编辑框数据 const visibleDrawer = ref(false) //显示或者隐藏 const drawerTile = ref('') //新增或者编辑 const productModel = ref({ id: 0, number: '', name: '', brand: '' }) const clearData = ()=>{ productModel.value = { id: 0, number: '', name: '', brand: '' } } //新增商品 const doAddProduct= ()=>{ addProduct(productModel.value).then(({data})=>{ if(data.statusCode==200){ ElMessage.success("添加成功") } clearData() visibleDrawer.value=false; productList(); }) } //编辑商品 const doUpdateProduct = () => { updateProduct(productModel.value).then((data)=>{ if(data.status==200){ ElMessage.success("编辑成功") } clearData() visibleDrawer.value=false; productList(); }) } /** * 打开编辑 */ const handleEdit = (row)=>{ visibleDrawer.value=true drawerTile.value="编辑商品" // 数据赋值给 model productModel.value = row; productModel.value.id= row.id } /** * 删除方法 */ const handleDelete = (row)=>{ ElMessageBox.confirm( '您确定删除这条数据么', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', } ) .then(() => { deleteProduct(row.id).then(({data})=>{ if(data.statusCode==200){ productList(); ElMessage({ type: 'success', message: '删除成功', }) } }) }) .catch(() => { ElMessage({ type: 'info', message: '取消删除', }) }) } </script> <style scoped> .card-header { display: flex; justify-content: space-between; align-items: center; } </style>
本文作者:千夜ん
本文链接:https://www.cnblogs.com/fengpeng123/p/18425058
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步