Vue3+Spring Boot技术栈,前端提交混合表单数据(普通字段+文件字段),上传文件,后端插入数据,将文件保存到数据库
一、技术栈
1、前端 Vue3 + Element Plus + TypeSprict
2、后端 Spring Boot 3.2.12 + Mybatis Plus
3、模型特点
3.1、表格展示列表数据
3.2、行点击,弹出对话框
3.3、前端使用 FormData 提交混合表单数据,包含普通字段和文件字段
3.4、文件对应数据库结构类型为 image
3.5、Spring MVC 注解 @RequestPart、@ModelAttribute
2、应用效果
3、Vue3 前端
对话框表单 QualityFileInfoDialog.vue
<script setup lang="ts" name="QualityFileInfoDialog">
......
// 上传,防抖
const onUploadClick = debounce(() => {// 模拟点击元素if (fileInputRef.value) {// 重置以允许重复选择相同文件fileInputRef.value.value = "";fileInputRef.value.click();}},1000,{ leading: true, trailing: true, maxWait: 1000 }
);// 点击【上传】触发,实现 SQL Server image 类型文件上传
const handleUpload = async (e: Event) => {// 打印 FormData 表单数据的内容// FormData对象不能直接通过 console.log(formData)输出完整内容(控制台仅显示 FormData {}的抽象表示)// console.log("formData = ", formData);// 使用 Object.fromEntries()将 FormData 转为普通对象,再通过 console.log 打印完整内容// const data = Object.fromEntries(formData.entries());// console.log(data);// 清空 FormData 表单数据的内容:遍历删除所有字段// formData.keys() 返回的迭代器会实时跟踪 FormData的当前状态。当调用 delete(key) 后,迭代器的内部指针可能因数据变化而跳过后续键。// 先将将迭代器转为静态数组,避免动态变化的影响// 使用 Array.from() 将迭代器转为静态数组// const keys = Array.from(formData.keys());// 使用 扩展运算符 将迭代器转为静态数组// const keys = [...formData.keys()];// for (let key of keys) {// formData.delete(key);// }// 清空 FormData 表单数据的内容:重新赋值,创建新实例,旧数据被丢弃(完全清空),需要使用 let 声明对象,不能使用 const 声明对象formData = new FormData();// 获取文件对象const input = e.target as HTMLInputElement;if (!input.files?.length) return;const file = input.files[0];// 校验文件大小if (file.size > 1024 * 1024 * 10) {ElMessage.warning("文件大小不能超过10MB");return;}if (file) {// 获取文件名的扩展名(后缀)extension.value = getExtension(file.name);// 新增模式if (props.isNew) {if (upperCase(extension.value) === upperCase("pdf")) {// 将文件对象 file 添加到 formData 对象中,uploadFile 需要与后端接口中接收文件的参数名一致,如果不一致,则后端需要指定参数名,如 @RequestPart("uploadFile") MultipartFile fileformData.append("uploadFile", file);} else if (upperCase(extension.value) === upperCase("xls") || upperCase(extension.value) === upperCase("xlsx")) {// 将文件对象 file 添加到 formData 对象中,uploadFile 需要与后端接口中接收文件的参数名一致,如果不一致,则后端需要指定参数名,如 @RequestPart("uploadFile") MultipartFile fileformData.append("uploadFile", file);// 将普通对象 qualityFileObj 的属性添加到 formData 对象中formData.append("fileNo", qualityFileObj.value.fileNo);formData.append("fileName", qualityFileObj.value.fileName);formData.append("edition", qualityFileObj.value.edition as string);formData.append("orderNo", qualityFileObj.value.orderNo as string);formData.append("issueDept", qualityFileObj.value.issueDept as string);formData.append("issueDate", qualityFileObj.value.issueDate as string);formData.append("smallCategory", qualityFileObj.value.smallCategory as string);formData.append("detailCategory", qualityFileObj.value.detailCategory as string);formData.append("modifyRecord", qualityFileObj.value.modifyRecord as string);formData.append("remark", qualityFileObj.value.remark as string);} else {// 将文件对象 file 添加到 formData 对象中,uploadFile 需要与后端接口中接收文件的参数名一致,如果不一致,则后端需要指定参数名,如 @RequestPart("uploadFile") MultipartFile fileformData.append("uploadFile", file);// 将普通对象 qualityFileObj 转换为 json 字符串 添加到 formData 对象中formData.append("qualityFile", JSON.stringify(qualityFileObj.value));}}// 查改模式else {if (upperCase(extension.value) === upperCase("pdf")) {// 将文件对象 file 添加到 formData 对象中,uploadFile 需要与后端接口中接收文件的参数名一致,如果不一致,则后端需要指定参数名,如 @RequestPart("uploadFile") MultipartFile fileformData.append("uploadFile", file);// 无需点击确定,直接发送请求,上传文件到数据库,实现 SQL Server image 类型文件上传await qualityFileUploadFileWithPutService(qualityFileObj.value.fileNo, formData);} else {// 将文件对象 file 添加到 formData 对象中,uploadFile 需要与后端接口中接收文件的参数名一致,如果不一致,则后端需要指定参数名,如 @RequestPart("uploadFile") MultipartFile fileformData.append("uploadFile", file);// 将普通对象 qualityFileObj 的 fileNo 属性添加到 formData 对象中formData.append("fileNo", qualityFileObj.value.fileNo);// 无需点击确定,直接发送请求,上传文件到数据库,实现 SQL Server image 类型文件上传await qualityFileUploadFileService(formData);}// 点击【上传/重传】选择文件后,上传文件完成,通知父组件更新文件路径名称和是否空内容的操作emit("upload-file-complete", file.name);}// 同步更新表单数据qualityFileObj.value.filePathname = file.name;qualityFileObj.value.isNullContent = false;}
};// 确定
const onConfirmClick = async () => {// 检查if (!check()) {return;}// 新增模式if (props.isNew) {if (upperCase(extension.value) === upperCase("pdf")) {// 发送请求,使用 put 发送请求,发送的数据有:请求体数据(文件数据 file),请求参数数据(普通对象数据 qualityFile)await qualityFileAddAttachUploadFileWithPutService(qualityFileObj.value, formData);} else if (upperCase(extension.value) === upperCase("xls") || upperCase(extension.value) === upperCase("xlsx")) {// 发送请求,使用 patch 发送请求,通过请求体发送表单数据 formData,表单数据,包含的数据有:文件数据(uploadFile)和// 普通对象的属性数据(fileNo、fileName、edition、orderNo、issueDept、issueDate、smallCategory、detailCategory、modifyRecord、remark)await qualityFileAddAttachUploadFileWithPatchService(formData);} else {// 发送请求,使用 post 发送请求,通过请求体发送表单数据 formData,表单数据,包含的数据有:文件数据(uploadFile)和 普通对象的json字符串数据(qualityFile)await qualityFileAddAttachUploadFileService(formData);}}// 查改模式else {// 两个对象不相同,需要更新数据;如果两个对象相同(所有属性值都相同),不需要更新数据if (!isEqual(props.qualityFileInfo, qualityFileObj.value)) {// 点击【确定】,确定质量体系文件信息,通知父组件执行相应的操作emit("confirm-quality-file", qualityFileObj.value);}}dialogVisible.value = false;
};
......
</script><template><el-dialogclass="quality-file-dialog"title="基础信息"width="640px"top="0vh"centerstyle="border-radius: 10px"v-model="dialogVisible":close-on-press-escape="true":close-on-click-modal="false":show-close="true"@close="onCancelClick"><template #default><el-form :model="qualityFileObj" label-width="auto" style="margin: 8px 16px"><el-row :gutter="10"><el-col :span="12"><el-form-item label="序号" label-position="right"><el-input v-model="qualityFileObj.orderNo" clearable /></el-form-item></el-col><el-col :span="12"><el-form-item label="文件编号" label-position="right"><el-input v-model="qualityFileObj.fileNo" clearable :disabled="!props.isNew" /></el-form-item></el-col></el-row><el-row :gutter="10"><el-col :span="24"><el-form-item label="文件名称" label-position="right"><el-input v-model="qualityFileObj.fileName" clearable /></el-form-item></el-col></el-row><el-row :gutter="10"><el-col :span="12"><el-form-item label="版本号" label-position="right"><el-input v-model="qualityFileObj.edition" clearable /></el-form-item></el-col><el-col :span="12"><el-form-item label="修改记录" label-position="right"><el-input v-model="qualityFileObj.modifyRecord" clearable /></el-form-item></el-col></el-row><el-row :gutter="10"><el-col :span="12"><el-form-item label="所属小类" label-position="right"><el-selectv-model="qualityFileObj.smallCategory"placeholder="请选择"clearable@clear="handleSmallCategoryClear"><el-option v-for="item in fileSmallCategoryList" :label="item.label" :value="item.value" /></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="所属类别" label-position="right"><el-selectv-model="qualityFileObj.detailCategory"placeholder="请选择"clearablefilterabledefault-first-option><el-option v-for="item in fileDetailCategoryList" :label="item.label" :value="item.label" /></el-select></el-form-item></el-col></el-row><el-row :gutter="10"><el-col :span="12"><el-form-item label="发布部门" label-position="right"><el-selectv-model="qualityFileObj.issueDept"placeholder="请选择"clearablefilterableallow-createdefault-first-option:value-on-clear="``"><el-option v-for="item in departmentList" :label="item.deptName" :value="item.deptName" /></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="发布日期" label-position="right"><el-date-pickerv-model="qualityFileObj.issueDate"type="date"format="YYYY-MM-DD"value-format="YYYY-MM-DD"clearablestyle="width: 100%" /></el-form-item></el-col></el-row><el-row :gutter="10"><el-col :span="24"><el-form-item label="备注" label-position="right"><el-input v-model="qualityFileObj.remark" clearable /></el-form-item></el-col></el-row><el-row :gutter="10"><el-col :span="15"><el-form-item label="附件" label-position="right"><el-input class="input-readonly" v-model="qualityFileObj.filePathname" readonly /></el-form-item></el-col><el-col :span="9"><el-form-item label="" label-position="right"><BasePreventReClickButton type="primary" plain :loading="false" @click="onUploadClick">{{qualityFileObj.isNullContent ? "上传" : "重传"}}</BasePreventReClickButton><BasePreventReClickButton:loading="false":disabled="qualityFileObj.isNullContent"@click="onDownloadClick">下载</BasePreventReClickButton><BasePreventReClickButtontype="danger"plain:loading="false":disabled="qualityFileObj.isNullContent"@click="onClearClick">清除</BasePreventReClickButton><!-- 文件输入元素,不显示,通过点击按钮【上传/重传】执行 onUploadClick,模拟点击该元素,从而触发 handleUpload 事件 --><input ref="fileInputRef" type="file" style="display: none" @change="handleUpload" /></el-form-item></el-col></el-row></el-form></template><!-- 模态框底部插槽,就算没有内容,也要写一个空的插槽,否则会影响布局 --><template #footer><div class="footer-div"><BasePreventReClickButton class="btn" type="primary" @click="onConfirmClick">确定</BasePreventReClickButton><el-button class="btn" @click="onCancelClick">取消</el-button></div></template></el-dialog>
</template><style scoped lang="scss">
.el-form {margin: 0 15px;
}// 设置等同于disabled的样式效果,背景色 #f5f7fa,字体颜色 #c0c4cc
// 设置类名为 input-readonly 的元素的背景颜色
.input-readonly :deep(.el-input__wrapper) {background-color: #f5f7fa;
}
// 设置只读的input的字体颜色,不使用类名,使用类属性选择器(.类名[属性名])
:deep(.el-input__inner[readonly]) {color: #c0c4cc;
}
</style>
qualityFile.ts
import request from "@/utils/request";
import type { IQualityFile, IQualityFileQueryObj } from "@/views/resources/QualityFile/types";/*** 新增质量体系文件信息,附带上传文件,使用 put 发送请求,发送的数据有:请求体数据(文件数据 uploadFile),请求参数数据(普通对象数据 qualityFile)* @param qualityFile 质量体系文件信息 {@link IQualityFile}* @param formData 表单数据,包含的数据只有:文件数据(uploadFile) {@link FormData}* @returns*/
export const qualityFileAddAttachUploadFileWithPutService = (qualityFile: IQualityFile, formData: FormData) => {// 发送请求,发送的数据有:请求体数据(文件数据 uploadFile),请求参数数据(普通对象数据 qualityFile)return request.put("/resources/qualityFile/addAttachUploadFile", formData, {params: qualityFile,// 上传文件,需设置 headers 信息,将"Content-Type"设置为"multipart/form-data"headers: {"Content-Type": "multipart/form-data"}});
};/*** 新增质量体系文件信息,附带上传文件,使用 patch 发送请求,通过请求体发送表单数据 formData* @param formData 表单数据,包含的数据有:文件数据(uploadFile)和* 普通对象的属性数据(fileNo、fileName、edition、orderNo、issueDept、issueDate、smallCategory、detailCategory、modifyRecord、remark) {@link FormData}* @returns*/
export const qualityFileAddAttachUploadFileWithPatchService = (formData: FormData) => {return request.patch("/resources/qualityFile/addAttachUploadFile", formData, {// 上传文件,需设置 headers 信息,将"Content-Type"设置为"multipart/form-data"headers: {"Content-Type": "multipart/form-data"}});
};/*** 新增质量体系文件信息,附带上传文件,使用 post 发送请求,通过请求体发送表单数据 formData* @param formData 表单数据,包含的数据有:文件数据(uploadFile)和 普通对象的json字符串数据(qualityFile) {@link FormData}* @returns*/
export const qualityFileAddAttachUploadFileService = (formData: FormData) => {return request.post("/resources/qualityFile/addAttachUploadFile", formData, {// 上传文件,需设置 headers 信息,将"Content-Type"设置为"multipart/form-data"headers: {"Content-Type": "multipart/form-data"}});
};
4、Spring Boot 后端
DTO
QualityFile.java
package com.weiyu.pojo;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;/*** 质量体系文件*/
@Schema(description = "质量体系文件实体")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QualityFile {@Schema(description = "文件唯一标识 id", example = "1")private Integer id;@Schema(description = "序号", example = "A00")private String orderNo;@Schema(description = "文件编号", example = "CZCDC/QM-2024-A0")private String fileNo;@Schema(description = "文件名称", example = "质量手册(封面)")private String fileName;@Schema(description = "版本号", example = "第9版")private String edition;@Schema(description = "修改记录", example = "第9版第0次修改")private String modifyRecord;@Schema(description = "所属小类", example = "3003")private String smallCategory;@Schema(description = "所属类别", example = "第九版")private String detailCategory;@Schema(description = "发布部门", example = "质量管理科")private String issueDept;@Schema(description = "发布日期", example = "2025-08-16")@JsonFormat(pattern = "yyyy-MM-dd")private LocalDate issueDate;@Schema(description = "备注", example = " ")private String remark;@Schema(description = "文件路径名称", example = "CZCDC∕QM-2018-B2 4.2 人员vVv+DW=dw.doc")private String filePathname;@Schema(description = "是否空内容", example = "true")private Boolean isNullContent;
}
QualityFileDTO.java
package com.weiyu.pojo;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;/*** 质量体系文件 DTO*/
@Schema(description = "质量体系文件 DTO")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QualityFileDTO {@Schema(description = "序号", example = "A00")private String orderNo;@Schema(description = "文件编号", example = "CZCDC/QM-2024-A0")private String fileNo;@Schema(description = "文件名称", example = "质量手册(封面)")private String fileName;@Schema(description = "版本号", example = "第9版")private String edition;@Schema(description = "修改记录", example = "第9版第0次修改")private String modifyRecord;@Schema(description = "所属小类", example = "3003")private String smallCategory;@Schema(description = "所属类别", example = "第九版")private String detailCategory;@Schema(description = "发布部门", example = "质量管理科")private String issueDept;@Schema(description = "发布日期", example = "2025-08-16")@JsonFormat(pattern = "yyyy-MM-dd")private LocalDate issueDate;@Schema(description = "备注", example = " ")private String remark;
}
控制层 QualityFileController.java
package com.weiyu.controller;import com.alibaba.fastjson.JSON;
import com.weiyu.anno.Debounce;
import com.weiyu.pojo.QualityFile;
import com.weiyu.pojo.QualityFileDTO;
import com.weiyu.pojo.QualityFileQueryDTO;
import com.weiyu.pojo.Result;
import com.weiyu.service.QualityFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.List;/*** 质量体系文件 Controller*/
@RestController
@RequestMapping("/resources/qualityFile")
@Slf4j
public class QualityFileController {@Autowiredprivate QualityFileService qualityFileService;/*** 新增质量体系文件,附带上传文件,使用 @PutMapping 接收请求,@ModelAttribute 接收参数* @ ModelAttribute是 Spring MVC 中处理复杂数据绑定和模型管理的核心注解,尤其适合表单操作和共享数据场景,能显著减少样板代码* 将 HTTP 请求参数(如表单字段、查询参数)自动绑定到 Java 对象的属性上* 示例说明:* 如果查询参数有fileNo为A1,表单字段也有fileNo为B2,那么qualityFile中的fileNo为B2,A1,即先获取表单字段,再获取查询参数,中间使用逗号分隔* MultipartFile参数名称说明:* 因为前端使用 formData.append("uploadFile", file) 用的参数名称是 uploadFile* 后端这里使用 uploadFile 与前端一致,可以不使用 @RequestPart("uploadFile"),也可以使用* @param qualityFile 质量体系文件 {@link QualityFile}* @param uploadFile 上传文件 {@link MultipartFile}*/@PutMapping("/addAttachUploadFile")public Result<?> addAttachUploadFile(@ModelAttribute QualityFile qualityFile,MultipartFile uploadFile) throws IOException {log.info("【质量体系文件】,新增附带上传文件,使用 @PutMapping 接收请求,@ModelAttribute 接收参数," +"/resources/qualityFile/addAttachUploadFile,qualityFile = {},uploadFile = {}", qualityFile, uploadFile);qualityFileService.addAttachUploadFile(qualityFile, uploadFile);return Result.success();}/*** 新增质量体系文件,附带上传文件,使用 @PatchMapping 接收请求,@ModelAttribute 接收参数* @ ModelAttribute是 Spring MVC 中处理复杂数据绑定和模型管理的核心注解,尤其适合表单操作和共享数据场景,能显著减少样板代码* 将 HTTP 请求参数(如表单字段、查询参数)自动绑定到 Java 对象的属性上* 示例说明:* 如果查询参数有fileNo为A1,表单字段也有fileNo为B2,那么qualityFile中的fileNo为B2,A1,即先获取表单字段,再获取查询参数,中间使用逗号分隔* MultipartFile参数名称说明:* 因为前端使用 formData.append("uploadFile", file) 用的参数名称是 uploadFile* 后端这里使用 uploadFile 与前端一致,可以不使用 @RequestPart("uploadFile"),也可以使用* @param qualityFileDTO 质量体系文件 DTO {@link QualityFileDTO}* @param uploadFile 上传文件 {@link MultipartFile}*/@PatchMapping("/addAttachUploadFile")public Result<?> addAttachUploadFile(@ModelAttribute QualityFileDTO qualityFileDTO,MultipartFile uploadFile) throws IOException {log.info("【质量体系文件】,新增附带上传文件,使用 @PatchMapping 接收请求,@ModelAttribute 接收参数," +"/resources/qualityFile/addAttachUploadFile,qualityFileDTO = {},uploadFile = {}", qualityFileDTO, uploadFile);QualityFile qualityFile = new QualityFile();qualityFile.setFileNo(qualityFileDTO.getFileNo());qualityFile.setFileName(qualityFileDTO.getFileName());qualityFile.setEdition(qualityFileDTO.getEdition());qualityFile.setOrderNo(qualityFileDTO.getOrderNo());qualityFile.setIssueDept(qualityFileDTO.getIssueDept());qualityFile.setIssueDate(qualityFileDTO.getIssueDate());qualityFile.setSmallCategory(qualityFileDTO.getSmallCategory());qualityFile.setDetailCategory(qualityFileDTO.getDetailCategory());qualityFile.setModifyRecord(qualityFileDTO.getModifyRecord());qualityFile.setRemark(qualityFileDTO.getRemark());qualityFileService.addAttachUploadFile(qualityFile, uploadFile);return Result.success();}/*** 新增质量体系文件,附带上传文件,使用 @PostMapping 接收请求,@RequestPart 接收参数* @ RequestPart是 Spring MVC 中处理 multipart 请求的灵活工具,尤其适合文件与结构化数据混合提交的场景,简化了数据绑定与异常处理* MultipartFile参数名称说明:* 因为前端使用 formData.append("uploadFile", file) 用的参数名称是 uploadFile* 后端这里使用 uploadFile 与前端一致,可以使用 @RequestPart("uploadFile"),也可以不使用* String参数名称说明:* 因为前端使用 formData.append("qualityFile", JSON.stringify(qualityFileObj.value)) 用的参数名称是 qualityFile* 后端这里使用 qualityFileJsonString 与前端不一致,必须使用 @RequestPart("qualityFile") 映射参数名称* @param qualityFileJsonString 质量体系文件json字符串* @param uploadFile 上传文件 {@link MultipartFile}*/@PostMapping("/addAttachUploadFile")public Result<?> addAttachUploadFile(@RequestPart("qualityFile") String qualityFileJsonString,@RequestPart("uploadFile") MultipartFile uploadFile) throws IOException {log.info("【质量体系文件】,新增附带上传文件,使用 @PostMapping 接收请求,@RequestPart 接收参数," +"/resources/qualityFile/addAttachUploadFile,qualityFileJsonString = {},uploadFile = {}",qualityFileJsonString, uploadFile);// json字符串 转换成 java对象(QualityFile)QualityFile qualityFile = JSON.parseObject(qualityFileJsonString, QualityFile.class);qualityFileService.addAttachUploadFile(qualityFile, uploadFile);return Result.success();}
}
服务层 QualityFileServiceImpl.java
package com.weiyu.service.impl;import com.weiyu.mapper.QualityFileMapper;
import com.weiyu.pojo.FileData;
import com.weiyu.pojo.QualityFile;
import com.weiyu.pojo.QualityFileQueryDTO;
import com.weiyu.service.QualityFileService;
import com.weiyu.utils.FileDownloadUtil;
import jakarta.validation.constraints.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** 质量体系文件 Service 接口实现*/
@Service
public class QualityFileServiceImpl implements QualityFileService {@Autowiredprivate QualityFileMapper qualityFileMapper;/*** 查询质量体系文件列表** @param queryDTO 查询 DTO* @return 质量体系文件列表*/@Overridepublic List<QualityFile> query(QualityFileQueryDTO queryDTO) {if (queryDTO == null) return new ArrayList<>();return qualityFileMapper.select(queryDTO);}/*** 新增质量体系文件** @param qualityFile 质量体系文件*/@Overridepublic void add(QualityFile qualityFile) {qualityFileMapper.insert(qualityFile);}/*** 上传质量体系文件** @param fileNo 文件编号* @param uploadFile 上传文件*/@Overridepublic void uploadFile(String fileNo, MultipartFile uploadFile) throws IOException {FileData fileData = new FileData();fileData.setFileName(uploadFile.getOriginalFilename());fileData.setFileContent(uploadFile.getBytes());// todo: 如果是大文件(超过10MB)保存到文件系统,数据库只保存文件路径;否则保存到数据库// 保存文件到数据库qualityFileMapper.saveFile(fileNo, fileData);}/*** 新增质量体系文件,附带上传文件** @param qualityFile 质量体系文件* @param uploadFile 上传文件*/@Override@Transactionalpublic void addAttachUploadFile(QualityFile qualityFile, MultipartFile uploadFile) throws IOException {// 新增质量体系文件add(qualityFile);// 上传质量体系文件uploadFile(qualityFile.getFileNo(), uploadFile);}
}
Mapper QualityFileMapper.java
package com.weiyu.mapper;import com.weiyu.pojo.FileData;
import com.weiyu.pojo.QualityFile;
import com.weiyu.pojo.QualityFileQueryDTO;
import org.apache.ibatis.annotations.Mapper;import java.util.List;/*** 质量体系文件 Mapper*/
@Mapper
public interface QualityFileMapper {/*** 查询质量体系文件列表* @param queryDTO 查询 DTO* @return 质量体系文件列表*/List<QualityFile> select(QualityFileQueryDTO queryDTO);/*** 新增质量体系文件* @param qualityFile 质量体系文件*/void insert(QualityFile qualityFile);/*** 保存质量体系文件数据到数据库* @param fileNo 文件编号* @param fileData 上传文件*/void saveFile(String fileNo, FileData fileData);
}
数据库sql操作 QualityFileMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.weiyu.mapper.QualityFileMapper"><!--mssql--><!-- 查询质量体系文件列表 --><select id="select" resultType="com.weiyu.pojo.QualityFile">selectCfm_OrderID as orderNo, Cfm_ID as fileNo, Cfm_Name as fileName, Cfm_Edition as edition,Cfm_ModifyRecord as modifyRecord, Cfm_SmallType as smallCategory, Cfm_SampleType as detailCategory,Cfm_Dept as issueDept, Cfm_IssueDate as issueDate, Cfm_Memo as remark,cfm_ContentFileName as filePathname, cfm_ContentIsNull as isNullContentfrom ControledFileMain<where>Cfm_BigType = '3'<if test="fileNo != null and fileNo != ''">and Cfm_ID like '%' + #{fileNo} + '%'</if><if test="fileName != null and fileName != ''">and Cfm_Name like '%' + #{fileName} + '%'</if></where>order by Cfm_SmallType, Cfm_ID</select><!-- 新增质量体系文件 --><insert id="insert">insert into ControledFileMain(Cfm_BigType, Cfm_OrderID, Cfm_ID, Cfm_Name, Cfm_Edition,Cfm_ModifyRecord, Cfm_SmallType, Cfm_SampleType,Cfm_Dept, Cfm_IssueDate, Cfm_Memo)values ('3', #{orderNo}, #{fileNo}, #{fileName}, #{edition},#{modifyRecord}, #{smallCategory}, #{detailCategory},#{issueDept}, #{issueDate}, #{remark})</insert><!-- 保存质量体系文件数据到数据库 --><update id="saveFile">update ControledFileMain setcfm_ContentFileName = #{fileData.fileName}, cfm_Content = #{fileData.fileContent}, cfm_ContentIsNull = 0where Cfm_BigType = '3' and Cfm_ID = #{fileNo}</update>
</mapper>
5、数据库表结构(sql server)
CREATE TABLE [dbo].[ControledFileMain]([Cfm_ID] [varchar](30) NOT NULL,[Cfm_Name] [varchar](200) NULL,[Cfm_BigType] [varchar](10) NOT NULL,[Cfm_SmallType] [varchar](10) NULL,[Cfm_Dept] [varchar](50) NULL,[Cfm_Memo] [varchar](100) NULL,[Cfm_ModifyRecord] [varchar](128) NULL,[Cfm_Edition] [varchar](50) NULL,[Cfm_IssueDate] [datetime] NULL,[Cfm_SampleType] [varchar](50) NULL,[Cfm_StandardType] [int] NULL,[Cfm_OrderID] [varchar](10) NULL,[Cfm_Holder] [varchar](50) NULL,[cfm_Content] [image] NULL,[cfm_ContentIsNull] [bit] NULL,[cfm_ContentFileName] [varchar](255) NULL,CONSTRAINT [PK_ControledFileMain] PRIMARY KEY CLUSTERED
([Cfm_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GO