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 树的概念与结构 概念ÿ…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
Git 命令全流程总结
以下是从初始化到版本控制、查看记录、撤回操作的 Git 命令全流程总结,按操作场景分类整理: 一、初始化与基础操作 操作命令初始化仓库git init添加所有文件到暂存区git add .提交到本地仓库git commit -m "提交描述"首次提交需配置身份git c…...
