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

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测试 报错 &#xff1a;postman调用时body参数中没有file单词 Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part file is…...

【机器人】机械臂轨迹和转矩控制对比

动力学控制和轨迹跟踪控制是机器人控制中的两个概念&#xff0c;它们在目标、方法和应用上有所不同&#xff0c;但也有一定关联。以下是它们的区别和联系&#xff1a; 1. 动力学控制 动力学控制是基于机器人动力学模型的控制方法&#xff0c;目标是控制机器人关节力矩或力&…...

如何利用矩阵化简平面上的二次型曲线

二次型曲线的定义 在二维欧式平面上&#xff0c;一个二次型曲线都可以写成一个关于 x , y x,y x,y的二元二次多项式&#xff1a; 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内核&#xff0c;一般有两种方法&#xff0c;一种是从EMMC启动&#xff0c;还有一种就是从SD卡启动&#xff0c;不断哪种启动方法&#xff0c;当开发板上电之后&#xff0c;首先运行的是uboot。 制作SD卡启动&#xff0c;首先要将uboot烧写到SD卡&#xff…...

sql server 数据库还原,和数据检查

右键数据库选择还原&#xff0c; 还原的备份文件必须选择在本地的文件&#xff08;远程文件没有试过&#xff09;还原数据库名字可以修改&#xff0c;然后file选择中有个2个目录data file 的目录 &#xff0c;和log data 的目录都可以重新选择还原到的新的目录&#xff0c;不要…...

工业大数据分析算法实战-day12

文章目录 day12时序分解STL&#xff08;季节性趋势分解法&#xff09;奇异谱分析&#xff08;SSA&#xff09;经验模态分解&#xff08;EMD&#xff09; 时序分割ChangpointTreeSplitAutoplait有价值的辅助 时序再表征 day12 今天是第12天&#xff0c;昨天主要是针对信号处理算…...

Hive其一,简介、体系结构和内嵌模式、本地模式的安装

目录 一、Hive简介 二、体系结构 三、安装 1、内嵌模式 2、测试内嵌模式 3、本地模式--最常使用的模式 一、Hive简介 Hive 是一个框架&#xff0c;可以通过编写sql的方式&#xff0c;自动的编译为MR任务的一个工具。 在这个世界上&#xff0c;会写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 为例&#xff0c;通过搜索得到默认安装版本信息&#xff1a; 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完成产品兼容性互认证

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

群晖利用acme.sh自动申请证书并且自动重载证书的问题解决

前言 21年的时候写了一个在群晖&#xff08;黑群晖&#xff09;下利用acme.sh自动申请Let‘s Encrypt的脚本工具 群晖使用acme自动申请Let‘s Encrypt证书脚本&#xff0c;自动申请虽然解决了&#xff0c;但是自动重载一直是一个问题&#xff0c;本人也懒&#xff0c;一想到去…...

质量小议51 - 茧房

茧房&#xff1a;茧房是指蚕茧所建的住所或空间&#xff0c;由一个蚕丝囊完全包裹住的一个密封的空间。 -- CSDN创作助手 信息茧房 - 指通过互联网和数字技术&#xff0c;将个人封闭在一个虚拟的信息环境中&#xff0c;使其只接收来自特定渠道的信息&#xff0c;而屏蔽其他信息…...

【C++图论】2359. 找到离给定两个节点最近的节点|1714

本文涉及知识点 C图论 打开打包代码的方法兼述单元测试 LeetCode2359. 找到离给定两个节点最近的节点 给你一个 n 个节点的 有向图 &#xff0c;节点编号为 0 到 n - 1 &#xff0c;每个节点 至多 有一条出边。 有向图用大小为 n 下标从 0 开始的数组 edges 表示&#xff0c…...

重拾设计模式-外观模式和适配器模式的异同

文章目录 目的不同适配器模式&#xff1a;外观模式&#xff1a; 结构和实现方式不同适配器模式&#xff1a;外观模式&#xff1a; 对客户端的影响不同适配器模式&#xff1a;外观模式&#xff1a; 目的不同 适配器模式&#xff1a; 主要目的是解决两个接口不兼容的问题&#…...

51c自动驾驶~合集42

我自己的原文哦~ https://blog.51cto.com/whaosoft/12888355 #DriveMM 六大数据集全部SOTA&#xff01;最新DriveMM&#xff1a;自动驾驶一体化多模态大模型&#xff08;美团&中山大学&#xff09; 近年来&#xff0c;视觉-语言数据和模型在自动驾驶领域引起了广泛关注…...

34 Opencv 自定义角点检测

文章目录 cornerEigenValsAndVecscornerMinEigenVal示例 cornerEigenValsAndVecs void cornerEigenValsAndVecs(InputArray src, --单通道输入8位或浮点图像OutputArray dst, --输出图像&#xff0c;同源图像或CV_32FC(6)int blockSize, --邻域大小值int ape…...

信创技术栈发展现状与展望:机遇与挑战并存

一、引言 在信息技术应用创新&#xff08;信创&#xff09;战略稳步推进的大背景下&#xff0c;我国信创技术栈已然在诸多关键层面收获了亮眼成果&#xff0c;不过也无可避免地遭遇了一系列亟待攻克的挑战。信创产业作为我国达成信息技术自主可控这一目标的关键一招&#xff0c…...

跟我学c++中级篇——C++中的缓存利用

一、缓存 学习过计算机知识的一般都知道缓存这个概念&#xff0c;大约也知道缓存是什么。但是如果是程序员&#xff0c;如何更好的利用缓存&#xff0c;可能就有很多人不太清楚了。其实缓存的目的非常简单&#xff0c;就是了更高效的操作数据。大家都听说过“局部性原理”&…...

二叉树_堆

目录 一. 树(非线性结构&#xff09; 1.1 树的概念与结构 1.2 树的表示 二. 二叉树 2.1 二叉树的概念与结构 2.2 特殊的二叉树 2.3 二叉树的存储结构 三. 实现顺序结构的二叉树 3.1 堆的概念与结构 一. 树(非线性结构&#xff09; 1.1 树的概念与结构 概念&#xff…...

word文档中有大量空白行删除不掉,怎么办?

现象&#xff1a; 分页之间的空白行太多了&#xff08; 按回车没用。删除也删除不掉 &#xff09; 解决办法&#xff1a; 按ctrl a 全选这个文档右击鼠标&#xff0c;点击【段落】选择【换行和分页】&#xff0c;然后把【分页】里的选项全部勾掉&#xff0c;然后点击【确定】…...

python rabbitmq实现简单/持久/广播/组播/topic/rpc消息异步发送可配置Django

windows首先安装rabbitmq 点击参考安装 1、环境介绍 Python 3.10.16 其他通过pip安装的版本(Django、pika、celery这几个必须要有最好版本一致) amqp 5.3.1 asgiref 3.8.1 async-timeout 5.0.1 billiard 4.2.1 celery 5.4.0 …...

构建高性能异步任务引擎:FastAPI + Celery + Redis

在现代应用开发中&#xff0c;异步任务处理是一个常见的需求。无论是数据处理、图像生成&#xff0c;还是复杂的计算任务&#xff0c;异步执行都能显著提升系统的响应速度和吞吐量。今天&#xff0c;我们将通过一个实际项目&#xff0c;探索如何使用 FastAPI、Celery 和 Redis …...

永磁同步电机无速度算法--全阶滑模观测器

一、原理介绍 在采用传统滑模观测器求取电机角度时通常存在系统抖振、低通滤波器导致角度相位滞后、角度的求取等问题。针对上述问题&#xff0c;本文采用全阶滑模观测器&#xff0c;该全阶滑模观测器具有二阶低通滤波器的特性&#xff0c;能有效滤除反电动势中的高频噪声&…...

部署开源大模型的硬件配置全面指南

目录 第一章:理解大型模型的硬件需求 1.1 模型部署需求分析 第二章:GPU资源平台 2.1 免费GPU资源 2.1.1 阿里云人工智能PAI 2.1.2 阿里天池实验室 2.1.3 Kaggle 2.1.4 Google Colab 2.2 付费GPU服务 2.2.1 AutoDL 2.2.2 Gpushare Cloud 2.2.3 Featurize 2.2.4 A…...

三、使用langchain搭建RAG:金融问答机器人--检索增强生成

经过前面2节数据准备后&#xff0c;现在来构建检索 加载向量数据库 from langchain.vectorstores import Chroma from langchain_huggingface import HuggingFaceEmbeddings import os# 定义 Embeddings embeddings HuggingFaceEmbeddings(model_name"m3e-base")#…...

Day13 用Excel表体验梯度下降法

Day13 用Excel表体验梯度下降法 用所学公式创建Excel表 用Excel表体验梯度下降法 详见本Day文章顶部附带资源里的Excel表《梯度下降法》&#xff0c;可以对照表里的单元格公式进行理解&#xff0c;还可以多尝试几次不同的学习率 η \eta η来感受&#xff0c;只需要更改学习率…...

计算机组成原理的学习笔记(5)--数据的表示与运算·其四 浮点数的储存和加减/内存对齐/大端小端

学习笔记 前言 本文主要是对于b站尚硅谷的计算机组成原理的学习笔记&#xff0c;仅用于学习交流。 1. 浮点数的表示与运算 规格化数&#xff1a; 浮点数的存储格式为 &#xff0c;其中&#xff1a; 为符号位。 为尾数&#xff0c;通常在0和1之间&#xff08;规格化形式为1.xx…...

华为IPD流程6大阶段370个流程活动详解_第二阶段:计划阶段 — 86个活动

华为IPD流程涵盖了产品从概念到上市的完整过程,各阶段活动明确且相互衔接。在概念启动阶段,产品经理和项目经理分析可行性,PAC评审后成立PDT。概念阶段则包括产品描述、市场定位、投资期望等内容的确定,同时组建PDT核心组并准备项目环境。团队培训涵盖团队建设、流程、业务…...

如何使用 Flask 框架创建简单的 Web 应用?

Flask是一个轻量级的Web应用框架&#xff0c;用Python编写&#xff0c;非常适合快速开发和原型设计。 它提供了必要的工具和技术来构建一个Web应用&#xff0c;同时保持核心简单&#xff0c;不强制使用特定的工具或库。 二、创建第一个Flask应用 安装Flask 首先&#xff0c…...