java 1.8+springboot文件上传+vue3+ts+antdv
1.参考
使用SpringBoot优雅的实现文件上传_51CTO博客_springboot 上传文件
2.postman测试
报错 :postman调用时body参数中没有file单词
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]
1)headers设置
Content-Type multipart/form-data; boundary=<calculated when request is sent>
2)body
选form-data
key中一定要有file单词,再在旁边文件中选择文件即可
浅析FormData.append()的使用、FormData对象常用方法、如何使用FormData传文件流传json对象传list数组、如何使用FormData传多个文件、如何打印FormData对象的内容_51CTO博客_FormData对象
3.报错
Files::getMd5
是Java NIO(New Input/Output)包中Files
类的一个静态方法,用于计算文件的MD5哈希值。这个方法在Java 17中引入,因此,要使用这个方法,你需要确保你的Java版本是17或更高。
4后端代码
controller
@PostMapping("/add")public ResponseResult addGoods(@RequestParam("name")String name,@RequestParam("categoryId")String categoryid,@RequestParam("file") MultipartFile file) throws IOException {//处理文件//获取文件原始名称String originalFilename = file.getOriginalFilename();System.out.println(originalFilename);//获取文件的类型String type = FileUtil.extName(originalFilename);
// log.info("文件类型是:" + type);//获取文件大小long size = file.getSize();//文件目录是否存在判断File uploadParentFile = new File(fileUploadPath);//判断文件目录是否存在if(!uploadParentFile.exists()) {//如果不存在就创建文件夹uploadParentFile.mkdirs();}//定义一个文件唯一标识码(UUID)String uuid = UUID.randomUUID().toString();String fileUUID = uuid + StrUtil.DOT + type;File uploadFile = new File(fileUploadPath + fileUUID);String url;//把上出来的文件转移到uploadFile中去file.transferTo(uploadFile);url = "http://localhost:8080/files/" + fileUUID;
// File uploadFile = new File(fileUploadPath + uuid + StrUtil.DOT + type);Goods goods=new Goods();goods.setName(name);goods.setCategoryId(Integer.parseInt(categoryid));goods.setFileurl(url);iGoodsService.save(goods);return ResponseResult.success(goods);}
service
package com.tencent.wxcloudrun.goods.service;import com.tencent.wxcloudrun.goods.entity.Goods;
import com.baomidou.mybatisplus.extension.service.IService;/*** <p>* 服务类* </p>** @author songhui* @since 2024-12-14*/
public interface IGoodsService extends IService<Goods> {}
serviceimpl
package com.tencent.wxcloudrun.goods.service.impl;import com.tencent.wxcloudrun.goods.entity.Goods;
import com.tencent.wxcloudrun.goods.mapper.GoodsMapper;
import com.tencent.wxcloudrun.goods.service.IGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;/*** <p>* 服务实现类* </p>** @author songhui* @since 2024-12-14*/
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {}
mapper
package com.tencent.wxcloudrun.goods.mapper;import com.tencent.wxcloudrun.goods.entity.Goods;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** <p>* Mapper 接口* </p>** @author songhui* @since 2024-12-14*/
public interface GoodsMapper extends BaseMapper<Goods> {}
entity
package com.tencent.wxcloudrun.goods.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;/*** <p>* * </p>** @author songhui* @since 2024-12-14*/
@TableName("sh_goods")
@ApiModel(value = "Goods对象", description = "")
public class Goods implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("商品id")@TableId(value = "id", type = IdType.AUTO)private Integer id;@ApiModelProperty("分类id")private Integer categoryId;@ApiModelProperty("SPU id")private Integer spuId;@ApiModelProperty("编号")private String sn;@ApiModelProperty("名称")private String name;@ApiModelProperty("关键词")private String keyword;@ApiModelProperty("图片")private String picture;@ApiModelProperty("提示")private String tips;@ApiModelProperty("描述")private String description;@ApiModelProperty("详情")private String content;@ApiModelProperty("价格")private BigDecimal price;@ApiModelProperty("库存")private Integer stock;@ApiModelProperty("评分")private BigDecimal score;@ApiModelProperty("是否上架")private Byte isOnSale;@ApiModelProperty("是否删除")private Byte isDel;@ApiModelProperty("是否包邮")private Byte isFreeShipping;@ApiModelProperty("销量计数")private Integer sellCount;@ApiModelProperty("评论计数")private Integer commentCount;@ApiModelProperty("上架时间")private Integer onSaleTime;@ApiModelProperty("创建时间")private Integer createTime;@ApiModelProperty("更新时间")private Integer updateTime;@ApiModelProperty("作者")private String author;@ApiModelProperty("文件地址")private String fileurl;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getCategoryId() {return categoryId;}public void setCategoryId(Integer categoryId) {this.categoryId = categoryId;}public Integer getSpuId() {return spuId;}public void setSpuId(Integer spuId) {this.spuId = spuId;}public String getSn() {return sn;}public void setSn(String sn) {this.sn = sn;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getKeyword() {return keyword;}public void setKeyword(String keyword) {this.keyword = keyword;}public String getPicture() {return picture;}public void setPicture(String picture) {this.picture = picture;}public String getTips() {return tips;}public void setTips(String tips) {this.tips = tips;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public BigDecimal getPrice() {return price;}public void setPrice(BigDecimal price) {this.price = price;}public Integer getStock() {return stock;}public void setStock(Integer stock) {this.stock = stock;}public BigDecimal getScore() {return score;}public void setScore(BigDecimal score) {this.score = score;}public Byte getIsOnSale() {return isOnSale;}public void setIsOnSale(Byte isOnSale) {this.isOnSale = isOnSale;}public Byte getIsDel() {return isDel;}public void setIsDel(Byte isDel) {this.isDel = isDel;}public Byte getIsFreeShipping() {return isFreeShipping;}public void setIsFreeShipping(Byte isFreeShipping) {this.isFreeShipping = isFreeShipping;}public Integer getSellCount() {return sellCount;}public void setSellCount(Integer sellCount) {this.sellCount = sellCount;}public Integer getCommentCount() {return commentCount;}public void setCommentCount(Integer commentCount) {this.commentCount = commentCount;}public Integer getOnSaleTime() {return onSaleTime;}public void setOnSaleTime(Integer onSaleTime) {this.onSaleTime = onSaleTime;}public Integer getCreateTime() {return createTime;}public void setCreateTime(Integer createTime) {this.createTime = createTime;}public Integer getUpdateTime() {return updateTime;}public void setUpdateTime(Integer updateTime) {this.updateTime = updateTime;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getFileurl() {return fileurl;}public void setFileurl(String fileurl) {this.fileurl = fileurl;}@Overridepublic String toString() {return "Goods{" +"id = " + id +", categoryId = " + categoryId +", spuId = " + spuId +", sn = " + sn +", name = " + name +", keyword = " + keyword +", picture = " + picture +", tips = " + tips +", description = " + description +", content = " + content +", price = " + price +", stock = " + stock +", score = " + score +", isOnSale = " + isOnSale +", isDel = " + isDel +", isFreeShipping = " + isFreeShipping +", sellCount = " + sellCount +", commentCount = " + commentCount +", onSaleTime = " + onSaleTime +", createTime = " + createTime +", updateTime = " + updateTime +", author = " + author +", fileurl = " + fileurl +"}";}
}
数据表
DROP TABLE IF EXISTS `sh_goods`;
CREATE TABLE `sh_goods` (`id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商品id',`category_id` int UNSIGNED NULL DEFAULT 0 COMMENT '分类id',`spu_id` int UNSIGNED NULL DEFAULT 0 COMMENT 'SPU id',`sn` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '编号',`name` varchar(120) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '名称',`keyword` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '关键词',`picture` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '图片',`tips` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '提示',`description` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '描述',`content` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '详情',`price` decimal(10, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '价格',`stock` int UNSIGNED NULL DEFAULT 0 COMMENT '库存',`score` decimal(3, 2) UNSIGNED NULL DEFAULT 0.00 COMMENT '评分',`is_on_sale` tinyint UNSIGNED NULL DEFAULT 0 COMMENT '是否上架',`is_del` tinyint UNSIGNED NULL DEFAULT 0 COMMENT '是否删除',`is_free_shipping` tinyint UNSIGNED NULL DEFAULT 0 COMMENT '是否包邮',`sell_count` int UNSIGNED NULL DEFAULT 0 COMMENT '销量计数',`comment_count` int UNSIGNED NULL DEFAULT 0 COMMENT '评论计数',`on_sale_time` int UNSIGNED NULL DEFAULT 0 COMMENT '上架时间',`create_time` int UNSIGNED NULL DEFAULT 0 COMMENT '创建时间',`update_time` int UNSIGNED NULL DEFAULT 0 COMMENT '更新时间',`author` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '作者',`fileurl` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '文件地址',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
pom.xml
<java.version>1.8</java.version>
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.tencent</groupId><artifactId>springboot-wxcloudrun</artifactId><version>1.0</version><name>springboot-wxcloudrun</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencyManagement><dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bom</artifactId><version>3.5.9</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-jsqlparser-4.9</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.33</version></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.11.0</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.14</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.13</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>3.3.5</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>3.0.3</version></dependency><dependency><groupId>io.swagger</groupId><artifactId>swagger-annotations</artifactId><version>1.6.14</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.17.1</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.9</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.33</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins><resources><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource></resources></build></project>
自动生成代码
package com.tencent;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.sql.Types;
import java.util.Collections;
public class CodeGenerator {public static void main(String[] args) {//修改位置1FastAutoGenerator.create("jdbc:mysql:///lvbo", "root", "123456").globalConfig(builder -> {//修改位置2builder.author("songhui") // 设置作者//修改位置3 关闭swagger.enableSwagger()
// .fileOverride() // 覆盖已生成文件//修改位置4.outputDir("D:\\git\\lvbo2\\src\\main\\java"); // 指定输出目录绝对路径,跟启动类一样的路径}).dataSourceConfig(builder ->builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {int typeCode = metaInfo.getJdbcType().TYPE_CODE;if (typeCode == Types.SMALLINT) {// 自定义类型转换return DbColumnType.INTEGER;}return typeRegistry.getColumnType(metaInfo);})).packageConfig(builder ->//修改位置5 必须放到主入口同一级别下,不然各种报错builder.parent("com.tencent.wxcloudrun")
// 设置父包名//****1修改位置6----------------------每次新表修改.moduleName("goods") // 设置父包模块名
// ****2修改位置7 指定xml文件存放位置.pathInfo(Collections.singletonMap(OutputFile.xml, "D:\\git\\lvbo2\\src\\main\\resources\\mapper\\goods")) // 设置mapperXml生成路径).strategyConfig(builder ->//修改位置8 意思是扫描这张表,并且生成实体类,如果不过滤TablePrefix,名字就会带前缀
//*****3 builder.addInclude("lvbo_user","lvbo_category") // 设置需要生成的表名builder.addInclude("sh_goods") // 设置需要生成的表名.addTablePrefix("sh_") // 设置过滤表前缀).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}}
// 表1 用户表(sh_user)
// 表2 商品分类表(sh_goods_category)
// 表3 商品表(sh_goods)
// 表4 商品spu表(sh_goods_spu)
// 表5 商品规格表(sh_goods_spec)
// 表6 商品规格项表(sh_goods_spec_item)
// 表7 商品规格项组合表(sh_goods_spec_set)
// 表8 商品属性表(sh_goods_attr)
// 表9 商品属性值表(sh_goods_attr_value)
// 表10 商品筛选表(sh_goods_selector)
// 表11 商品筛选值表(sh_goods_selector_value)
文件存储位置
D:\\git\\lvbo2\\src\\main\\java
为了试试能不能通过浏览器访问,所以放在这里了
生成地址举例
http://localhost:8080/files/0de91001-7cf5-4077-9ad2-db6abaf81d03.txt
5前端代码
有空精简
环境vue3 ts antdv
D:\code\lvbovue3frontpc3\src\request
axios.ts
import axios from 'axios'
import { showMessage } from "./status"; // 引入状态码文件
// https://zhuanlan.zhihu.com/p/398499423
// 创建axios实例
const request = axios.create({baseURL: 'http://localhost:8080',// 所有的请求地址前缀部分timeout: 80000, // 请求超时时间(毫秒)withCredentials: true,// 异步请求携带cookie// headers: {// 设置后端需要的传参类型// 'Content-Type': 'application/json',// 'token': x-auth-token',//一开始就要token// 'X-Requested-With': 'XMLHttpRequest',// },
})// request拦截器https://zhuanlan.zhihu.com/p/398499423
request.interceptors.request.use(config => {// 如果你要去localStor获取token,(如果你有)// let token = localStorage.getItem("x-auth-token");// if (token) {//添加请求头//config.headers["Authorization"]="Bearer "+ token// }return config},error => {// 对请求错误做些什么Promise.reject(error)}
)// response 拦截器
request.interceptors.response.use(response => {// 对响应数据做点什么return response.data},error => { // 对响应错误做点什么return Promise.reject(error)}
)export default request
api.ts
import { ref } from "vue";
import instance from "./axios";
import axios from "axios";//一般情况下,接口类型会放到一个文件
// 下面两个TS接口,表示要传的参数
interface ReqLogin {name: stringpaw: string
}
interface ReqStatus {id: stringnavStatus: string
}// Res是返回的参数,T是泛型,需要自己定义,返回对数统一管理***
type Res<T> = Promise<ItypeAPI<T>>;
// 一般情况下响应数据返回的这三个参数,
// 但不排除后端返回其它的可能性,
interface ItypeAPI<T> {data: T,//请求的数据,用泛型msg: string | null // 返回状态码的信息,如请求成功等code: number //返回后端自定义的200,404,500这种状态码
}// post请求 ,没参数
export const LogoutAPI = (): Res<null> => instance.post("/admin/logout");// post请求,有参数,如传用户名和密码
export const loginAPI = (data: ReqLogin): Res<string> =>instance.post("/admin/login", data);// post请求 ,没参数,但要路径传参
export const StatusAPI = (data: ReqStatus): Res<null> =>instance.post(`/productCategory?ids=${data.id}&navStatus=${data.navStatus}`);// get请求,没参数,
export const FlashSessionListApi = (): Res<null> =>instance.get("/flashSession/list");// get请求,有参数,路径也要传参 (也可能直接在这写类型,不过不建议,大点的项目会维护一麻烦)
export const ProductCategoryApi = (params: { parentId: number }): any =>instance.get(`/productCategory/list/${params.parentId}`, { params });// get请求,有参数,(如果你不会写类型也可以使用any,不过不建议,因为用了之后 和没写TS一样)
export const AdminListAPI = (params:any): any => instance.get("/admin/list", { params });// ------------------------------------文件目录操作------------------------------------------------interface Category {name: string,parentid:string,id:string
}// 查询目录export const CategoryListApi = (): Res<null> =>instance.get("/goods/goodsCategory/getAll");// 添加 post请求 ,参数,但要路径传参
export const AddCategoryAPI = (data: Category): Res<null> =>instance.post(`/goods/goodsCategory/add?name=${data.name}&parentid=${data.parentid}`);// 修改 post请求 ,参数,但要路径传参
export const updateCategoryAPI = (data: Category): Res<null> =>instance.put(`/goods/goodsCategory/update?name=${data.name}&id=${data.id}`);// 删除文件目录export const DelCategoryApi = (id:string): Res<null> =>instance.delete(`/goods/goodsCategory/del?id=${id}`);// ------------------------------------文件操作------------------------------------------------interface Goods {id:string,category_id:string,name: string,author:string,description:string,fileurl:string
}
interface insertbooks {category_id:string,name: string,}// 查询目录export const GoodsListApi = (): Res<null> =>instance.get("/goods/goods/getAll");//使用原始axios处理带参数文件请求
// const baseURL='http://localhost:8080'
// export function uploadFileWithFileds(param: any) {
// return axios.post(baseURL+'/good/good/add',param).then((res)=>{
// return res
// })
// }// 添加 post请求 ,参数,但要路径传参
// const formData = new FormData();
// export const AddGoodsAPI = (data: insertbooks): Res<null> =>{export const AddGoodsAPI = (formData:FormData)=>{instance.post("/goods/goods/add",formData);
}// 修改 post请求 ,参数,但要路径传参
export const updateGoodsAPI = (data: insertbooks): Res<null> =>instance.put(`/goods/goods/update?name=${data.name}&&categoryid=${data.category_id}`);// 删除文件目录export const DelGoodsApi = (id:string): Res<null> =>instance.delete(`/goods/goods/del?id=${id}`);
status.ts
export const showMessage = (status:number|string) : string => {let message:string = "";switch (status) {case 400:message = "请求错误(400)";break;case 401:message = "未授权,请重新登录(401)";break;case 403:message = "拒绝访问(403)";break;case 404:message = "请求出错(404)";break;case 408:message = "请求超时(408)";break;case 500:message = "服务器错误(500)";break;case 501:message = "服务未实现(501)";break;case 502:message = "网络错误(502)";break;case 503:message = "服务不可用(503)";break;case 504:message = "网络超时(504)";break;case 505:message = "HTTP版本不受支持(505)";break;default:message = `连接出错(${status})!`;}return `${message},请检查网络或联系管理员!`;
};
//https://cloud.tencent.com/developer/article/1916167
view
主要是用a-form包裹了 a upload
<a-uploadv-model:file-list="fileList"name="文件上传":beforeUpload="beforeUpload"><a-button> 选择文件 </a-button></a-upload>
先定一个formData
用于准备所有信息(包括文件)给axios发送
const formData=new FormData();
FormData应该是一种比较好用的js新格式,参考
https://juejin.cn/post/7258171660145803324
获得file
这里的:beforeUpload特别重要,主要是 其获得了上传的file
const beforeUpload=(file)=>{formData.append('file',file)}
formdata.append既可以添加属性给它,也可以添加文件
formstate
用于收集非附件的其它form字段信息
因为文件上传框是个弹出框,所以用了a-modal
<a-modal>
<a-form>
<a-form-item>
<a-upload>
给a-form绑定了一个属性formstate
<template><div style="margin-left: 16px"><div style="margin-bottom: 16px"><a-button type="primary" :disabled="!hasSelected" :loading="state.loading" @click="start">Reload</a-button><!-- 因为选中的要删除的行的id存在state.selectedRowKeys里面 --><a-button type="primary" @click="delBook(state.selectedRowKeys)">删除书籍</a-button><a-button type="primary" @click="addBook">新增书籍</a-button><span style="margin-left: 8px"><template v-if="hasSelected">{{ `Selected ${state.selectedRowKeys.length} items` }}</template></span></div><!--必须指定rowKey,可以是当前data中的一个属性 ,不指定的话就会被全部选中--><a-tablerowKey="id":row-selection="{ selectedRowKeys: state.selectedRowKeys, onChange: onSelectChange }":columns="columns":data-source="data"/></div><!-- 弹出框 a-modal 默认隐藏,是在ContextMenuClick让其显示出来--><a-modalv-model:open="open":title="modalTitle"@ok="handleOk"@cancel="resetForm"okText="确认"cancelText="取消":maskClosable="false":closable="false"><a-formref="formRef":model="formState":rules="rules":label-col="labelCol":wrapper-col="wrapperCol"><a-form-item ref="categoryId" label="分类编号" name="categoryId"><a-inputv-model:value="formState.categoryId"placeholder="分类编号"/></a-form-item><a-form-item ref="name" label="书名" name="name"><a-inputv-model:value="formState.name"placeholder="书名"/></a-form-item><a-form-item ref="author" label="作者" name="author"><a-inputv-model:value="formState.author"placeholder="作者"/></a-form-item><a-form-item ref="description" label="简介" name="description"><a-inputv-model:value="formState.description"placeholder="简介"/></a-form-item><a-form-item name="fileList" label="上传文件"><!-- <a-uploadv-model:file-list="fileList"name="文件上传"action="":customRequest="upDown":beforeUpload="beforeUpload"@remove="removeFile"accept=".xlsx,.xls"> --><a-uploadv-model:file-list="fileList"name="文件上传":beforeUpload="beforeUpload"><a-button> 选择文件 </a-button></a-upload> </a-form-item></a-form></a-modal></template><script lang="ts" setup>import { message, Modal, Upload} from 'ant-design-vue';
import { computed, onMounted, reactive, ref, toRaw } from 'vue';
import { AddGoodsAPI, DelGoodsApi, GoodsListApi, updateGoodsAPI, uploadFileWithFileds } from '../../request/api';
const props = defineProps({parentData: String
});type Key = string | number;interface DataType {key: Key;categoryId:string,name: string;author: string;description: string;fileurl:string;}const columns = [{title: '分类',dataIndex: 'categoryId',},{title: '书名',dataIndex: 'name',},{title: '作者',dataIndex: 'author',},{title: '简介',dataIndex: 'description',},];let data=ref<DataType[]>([]);// for (let i = 0; i < 46; i++) {// data.push({// key: i,// name: `Edward King ${i}`,// age: 32,// address: `London, Park Lane no. ${i}`,// });// }//open代替了visible
const open = ref(false);const modalTitle = ref("新增书籍");const formRef = ref();// 重要的formStateconsole.log("props.parentData",props.parentData)//文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件文件//存储文件const fileList = ref<any[]>([]);// 自定义上传,可以自定义上传接口,不用通过action属性,还是非常灵活的const customRequestMethod=(file:File)=> {// const { onSuccess, onError, file, onProgress } = options;const formData=new FormData();}//
const formData=new FormData();const formState = reactive({name:'',categoryId: '',description:'',author:'',});const beforeUpload=(file)=>{formData.append('file',file)}//https://blog.csdn.net/dashinihao/article/details/118630567// const fileList = ref<UploadProps['fileList']>()interface FileInfo {uid: string;name: string;status?: string;// 其他可能的属性...
}// const fileList=[]const rules = {name: [{required: false,message: "请输入父节点编号",trigger: "blur",},],};const resetForm = () => {// formRef.value.resetFields();};const handleOk = () => {if (modalTitle.value == "新增书籍") {// const formData = ref(new FormData());formData.append('name',formState.name);formData.append('categoryId',formState.categoryId);console.log("name----",formData.get('name'))console.log("hell0----",formData.get('file'))//新增文件// uploadFileWithFileds(formData)AddGoodsAPI(formData)}}// const handleOk = (e) => {
// console.log(e);
// // console.log("hello");
// formRef.value
// .validate()
// .then(() => {
// console.log("values", formState, toRaw(formState), e);
// if (modalTitle.value == "新增书籍") {
// //新增文件
// AddGoodsAPI({// name: formState.name,
// category_id: formState.categoryId// })
// .then((res) => {
// if (res.data.status == 0) {
// message.error("请修改");
// } else {
// message.success("上传成功")// }
// })
// .catch(() => {
// message.error("新增失败请联系管理员");
// })
// .finally(() => {
// resetForm();
// open.value = false;
// });
// } else {
// //修改文件
// updateGoodsAPI(
// {
// name: formState.name,
// category_id:''// }
// )
// .then((res) => {
// if (res.data.status == 200) {// message.success("修改成功");
// }
// else {
// message.error("修改失败请联系管理员");
// }
// })
// .catch(() => {
// message.error("修改失败请联系管理员");
// })
// .finally(() => {
// resetForm();
// open.value = false;
// });
// }
// })
// .catch((error) => {
// console.log("error", error);
// });
// };onMounted(()=>getData()
)const getData=async () => {await GoodsListApi().then(response=>{// console.log("res",response.data)// x.value=response.data;// data.value=response.data;data.value=response.data;console.log(data)} );}const state = reactive<{selectedRowKeys: Key[];loading: boolean;}>({selectedRowKeys: [], // Check here to configure the default columnloading: false,});const hasSelected = computed(() => state.selectedRowKeys.length > 0);const start = () => {state.loading = true;// ajax request after empty completingsetTimeout(() => {state.loading = false;state.selectedRowKeys = [];}, 1000);};const onSelectChange = (selectedRowKeys: Key[]) => {console.log('selectedRowKeys changed: ', selectedRowKeys);state.selectedRowKeys = selectedRowKeys;console.log("当前选择",state.selectedRowKeys)};//删除const delBook=(key:any)=>{Modal.confirm({title: '确认删除此数据?',// icon: createVNode(IconComponent),onOk() {DelGoodsApi(key).then(res => {if (res.data.code === 0) {message.success("删除成功")// subareaList()} else {message.error(res.data.msg)}})},onCancel() { },})}//添加const addBook=()=>{open.value=true }</script>
发给axios
由a-modal上的handleOk来触发调用后端
<a-modalv-model:open="open":title="modalTitle"@ok="handleOk"@cancel="resetForm"okText="确认"cancelText="取消":maskClosable="false":closable="false">
AddGoodsAPI(formData)
相关文章:

java 1.8+springboot文件上传+vue3+ts+antdv
1.参考 使用SpringBoot优雅的实现文件上传_51CTO博客_springboot 上传文件 2.postman测试 报错 :postman调用时body参数中没有file单词 Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part file is…...
【机器人】机械臂轨迹和转矩控制对比
动力学控制和轨迹跟踪控制是机器人控制中的两个概念,它们在目标、方法和应用上有所不同,但也有一定关联。以下是它们的区别和联系: 1. 动力学控制 动力学控制是基于机器人动力学模型的控制方法,目标是控制机器人关节力矩或力&…...
如何利用矩阵化简平面上的二次型曲线
二次型曲线的定义 在二维欧式平面上,一个二次型曲线都可以写成一个关于 x , y x,y x,y的二元二次多项式: F ( x , y ) a 11 x 2 2 a 12 x y a 22 y 2 2 a 1 x 2 a 2 y a 0 0 \begin{equation} F(x,y)a_{11}x^22a_{12}xya_{22}y^22a_1x2a_2ya_00…...

【系统移植】制作SD卡启动——将uboot烧写到SD卡
在开发板上启动Linux内核,一般有两种方法,一种是从EMMC启动,还有一种就是从SD卡启动,不断哪种启动方法,当开发板上电之后,首先运行的是uboot。 制作SD卡启动,首先要将uboot烧写到SD卡ÿ…...

sql server 数据库还原,和数据检查
右键数据库选择还原, 还原的备份文件必须选择在本地的文件(远程文件没有试过)还原数据库名字可以修改,然后file选择中有个2个目录data file 的目录 ,和log data 的目录都可以重新选择还原到的新的目录,不要…...

工业大数据分析算法实战-day12
文章目录 day12时序分解STL(季节性趋势分解法)奇异谱分析(SSA)经验模态分解(EMD) 时序分割ChangpointTreeSplitAutoplait有价值的辅助 时序再表征 day12 今天是第12天,昨天主要是针对信号处理算…...

Hive其一,简介、体系结构和内嵌模式、本地模式的安装
目录 一、Hive简介 二、体系结构 三、安装 1、内嵌模式 2、测试内嵌模式 3、本地模式--最常使用的模式 一、Hive简介 Hive 是一个框架,可以通过编写sql的方式,自动的编译为MR任务的一个工具。 在这个世界上,会写SQL的人远远大于会写ja…...

LSTM-SVM时序预测 | Matlab基于LSTM-SVM基于长短期记忆神经网络-支持向量机时间序列预测
LSTM-SVM时序预测 | Matlab基于LSTM-SVM基于长短期记忆神经网络-支持向量机时间序列预测 目录 LSTM-SVM时序预测 | Matlab基于LSTM-SVM基于长短期记忆神经网络-支持向量机时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.LSTM-SVM时序预测 | Matlab基于LSTM…...
MacPorts 中安装高/低版本软件方式,以 RabbitMQ 为例
查询信息 这里以 RabbitMQ 为例,通过搜索得到默认安装版本信息: port search rabbitmq-server结果 ~/Downloads> port search rabbitmq-server rabbitmq-server 3.11.15 (net)The RabbitMQ AMQP Server ~/Downloads>获取二进制文件 但当前官网…...

CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
Strong Transferable Adversarial Attacks via Ensembled Asymptotically Normal Distribution Learning 摘要-Abstract引言-Introduction相关工作及前期准备-Related Work and Preliminaries1. 黑盒对抗攻击2. SGD的渐近正态性 提出的方法-Proposed Method随机 BIM 的渐近正态…...

建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
近日,经与腾讯云联合测试,建投数据自主研发的人力资源信息管理系统V3.0、招聘管理系统V3.0、绩效管理系统V2.0、培训管理系统V3.0通过腾讯云数据库TDSQL的技术认证,符合腾讯企业标准的要求,产品兼容性良好,性能卓越。 …...

群晖利用acme.sh自动申请证书并且自动重载证书的问题解决
前言 21年的时候写了一个在群晖(黑群晖)下利用acme.sh自动申请Let‘s Encrypt的脚本工具 群晖使用acme自动申请Let‘s Encrypt证书脚本,自动申请虽然解决了,但是自动重载一直是一个问题,本人也懒,一想到去…...
质量小议51 - 茧房
茧房:茧房是指蚕茧所建的住所或空间,由一个蚕丝囊完全包裹住的一个密封的空间。 -- CSDN创作助手 信息茧房 - 指通过互联网和数字技术,将个人封闭在一个虚拟的信息环境中,使其只接收来自特定渠道的信息,而屏蔽其他信息…...

【C++图论】2359. 找到离给定两个节点最近的节点|1714
本文涉及知识点 C图论 打开打包代码的方法兼述单元测试 LeetCode2359. 找到离给定两个节点最近的节点 给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,每个节点 至多 有一条出边。 有向图用大小为 n 下标从 0 开始的数组 edges 表示,…...
重拾设计模式-外观模式和适配器模式的异同
文章目录 目的不同适配器模式:外观模式: 结构和实现方式不同适配器模式:外观模式: 对客户端的影响不同适配器模式:外观模式: 目的不同 适配器模式: 主要目的是解决两个接口不兼容的问题&#…...

51c自动驾驶~合集42
我自己的原文哦~ https://blog.51cto.com/whaosoft/12888355 #DriveMM 六大数据集全部SOTA!最新DriveMM:自动驾驶一体化多模态大模型(美团&中山大学) 近年来,视觉-语言数据和模型在自动驾驶领域引起了广泛关注…...
34 Opencv 自定义角点检测
文章目录 cornerEigenValsAndVecscornerMinEigenVal示例 cornerEigenValsAndVecs void cornerEigenValsAndVecs(InputArray src, --单通道输入8位或浮点图像OutputArray dst, --输出图像,同源图像或CV_32FC(6)int blockSize, --邻域大小值int ape…...

信创技术栈发展现状与展望:机遇与挑战并存
一、引言 在信息技术应用创新(信创)战略稳步推进的大背景下,我国信创技术栈已然在诸多关键层面收获了亮眼成果,不过也无可避免地遭遇了一系列亟待攻克的挑战。信创产业作为我国达成信息技术自主可控这一目标的关键一招,…...
跟我学c++中级篇——C++中的缓存利用
一、缓存 学习过计算机知识的一般都知道缓存这个概念,大约也知道缓存是什么。但是如果是程序员,如何更好的利用缓存,可能就有很多人不太清楚了。其实缓存的目的非常简单,就是了更高效的操作数据。大家都听说过“局部性原理”&…...

二叉树_堆
目录 一. 树(非线性结构) 1.1 树的概念与结构 1.2 树的表示 二. 二叉树 2.1 二叉树的概念与结构 2.2 特殊的二叉树 2.3 二叉树的存储结构 三. 实现顺序结构的二叉树 3.1 堆的概念与结构 一. 树(非线性结构) 1.1 树的概念与结构 概念ÿ…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...