前端:
主页面----引用弹窗:
</template>
<view>
<view>
<el-button type="primary" plain @click="handleImport">
<Icon icon="ep:plus" />导入
</el-button>
</view>
<ImportModel ref="importFormRef" @success="handleInit" />
<view>
</template>
<script>
const handleImport = () => {
importFormRef.value.open() // 打开引入文件弹窗
}
const handleInit = () => {
init() //刷新页面数据
}
</script>
子页面----上传文件弹窗:
<template>
<Dialog v-model="dialogVisible" title="信息导入" width="400">
<el-upload
ref="uploadRef"
v-model:file-list="fileList"
:auto-upload="false"
:multiple="true"
:disabled="formLoading"
:headers="uploadHeaders"
:on-error="submitFormError"
:on-exceed="handleExceed"
:on-change="handleChange"
:on-success="submitFormSuccess"
:before-upload="beforeColorUpload"
:http-request="uploadFiles"
accept=".xlsx, .xls"
drag
>
<Icon icon="ep:upload" />
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancelUpload">取 消</el-button>
</template>
</Dialog>
</template>
<script lang="ts" name="ImportForm" setup>
import { getAccessToken, getTenantId } from '@/utils/auth'
import importInfo from '@/api/cloud/checkTem/index'
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const formLoading = ref(false) // 表单的加载中
const uploadRef = ref()
const uploadHeaders = ref() // 上传 Header 头
const fileList = ref([]) // 文件列表
const state = reactive({
uploadEle: null as Element | null,
uploadList: []
})
const handleChange = async (file, fileList) => {
fileList.value = file
}
/** 打开弹窗 */
const open = () => {
dialogVisible.value = true
formLoading.value = false // 每次允许上传
nextTick(() => {
state.uploadEle = document.querySelector('.el-upload__input')
state.uploadEle.webkitdirectory = true
})
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
const uploadFiles = async () => {
console.log('进入uploadFiles')
}
/** 提交表单 */
const submitForm = async () => {
if (fileList.value.length == 0) {
message.error('请上传文件')
return
}
// // 提交请求
uploadHeaders.value = {
Authorization: 'Bearer ' + getAccessToken(),
'tenant-id': getTenantId()
}
submitFormSuccess({ code: 0 })
}
/** 文件上传成功 */
const emits = defineEmits(['success'])
const submitFormSuccess = async (response: any) => {
console.log('submitFormSuccess')
if (response.code !== 0) {
message.error(response.msg)
formLoading.value = false
return
}
let formData = new FormData()
formData.append('name', 'myk')
fileList.value.forEach((item) => {
formData.append('file', item.raw)
})
formLoading.value = true
await importInfo(formData)
.then(() => {
message.success('导入成功')
formLoading.value = false
// uploadRef.value.clearFiles()
})
.catch((res) => {
formLoading.value = false
})
dialogVisible.value = false
unref(uploadRef)?.clearFiles()
emits('success')
}
const beforeColorUpload = async () => {
unref(uploadRef)?.clearFiles()
}
/** 上传错误提示 */
const submitFormError = (): void => {
message.error('上传失败,请您重新上传!')
formLoading.value = false
}
/** 文件数超出提示 */
const handleExceed = (): void => {
message.error('最多只能上传一个文件!')
}
const cancelUpload = async () => {
unref(uploadRef)?.clearFiles()
dialogVisible.value = false
}
</script>
axios接口
import request from '@/config/axios'
// 导入设备模板维护
export const importEquTemObject = (formData) => {
return request.upload({
url: '/url/url/import',
data: formData
})
}
获取权限js{看框架如何调用权限来更改}
/**
* 配置浏览器本地存储的方式,可直接存储对象数组。
*/
import WebStorageCache from 'web-storage-cache'
type CacheType = 'localStorage' | 'sessionStorage'
export const CACHE_KEY = {
IS_DARK: 'isDark',
USER: 'user',
LANG: 'lang',
THEME: 'theme',
LAYOUT: 'layout',
ROLE_ROUTERS: 'roleRouters',
DICT_CACHE: 'dictCache'
}
export const useCache = (type: CacheType = 'localStorage') => {
const wsCache: WebStorageCache = new WebStorageCache({
storage: type
})
return {
wsCache
}
}
// 第二个js引用
import { useCache } from '@/hooks/web/useCache'
const { wsCache } = useCache()
// 获取token
export const getAccessToken = () => {
// 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错
return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN')
}
// 刷新token
export const getRefreshToken = () => {
return wsCache.get(RefreshTokenKey)
}
// ========== 租户相关 ==========
const TenantIdKey = 'TENANT_ID'
const TenantNameKey = 'TENANT_NAME'
export const getTenantId = () => {
return wsCache.get(TenantIdKey)
}
export const setTenantId = (username: string) => {
wsCache.set(TenantIdKey, username)
}
后端 :
Spring Boot框架 | 建立MUltpartFile类用于接收excel文件
package org.springframework.web.multipart;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.FileCopyUtils;
public interface MultipartFile extends InputStreamSource {
String getName();
@Nullable
String getOriginalFilename();
@Nullable
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws IOException;
@Override
InputStream getInputStream() throws IOException;
default Resource getResource() {
return new MultipartFileResource(this);
}
void transferTo(File dest) throws IOException, IllegalStateException;
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
}
controller
@PostMapping("import")
@Operation(summary = "导入")
@Parameters(
@Parameter(name = "file", description = "Excel 文件", required = true)
)
public CommonResult<CheckBaseProjectImportRespVO> importEXCEL(
@RequestParam("file") MultipartFile[] files) throws Exception {
return success(importService.importBaseProject(files));
}
// service:
CheckBaseProjectImportRespVO importBaseProject(MultipartFile[] files) throws Exception;
导入VO类
// 传入进来的importVo类
package cn.iocoder.yudao.base.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
public class BaseProjectImportVO {
@ExcelProperty("学生姓名") // 导入的列名
@NotNull(message = "学生姓名不可为空!")
private String name;
@ExcelProperty("学生年龄") // 导入的列名
@NotNull(message = "学生年龄不可为空!")
private String age;
@ExcelProperty("成绩") // 导入的列名
@NotNull(message = "成绩不可为空!")
private String score;
@ExcelProperty("选项内容")
private String options;
}
返回的结果集
package cn.iocoder.yudao.base.BaseVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data // 继承需要返回的基础数据
public class importResVO extends BaseVo{
@Schema(description = "创建成功的数组", requiredMode = Schema.RequiredMode.REQUIRED)
private List<String> names;
@Schema(description = "导入失败的用户集合,key 为用户名,value 为失败原因",
requiredMode = Schema.RequiredMode.REQUIRED)
private Map<String, String> failNames;
}
实现方法
@Override
@Transactional(rollbackFor = Exception.class) // 必须添加事务!!
public ImportResVo importBaseProject(MultipartFile[] files) throws Exception {
// 筛选出文件名包含 "学生信息导入" 的文件
List<MultipartFile> ftFiles = Arrays.stream(files).filter(ft ->
ft.getOriginalFilename().contains("学生信息导入")).collect(Collectors.toList());
if(ftFiles.isEmpty()){
throw exception(ALL,"请上传文件名包含【学生信息导入】的文件" );
}
// 读取 Excel 文件并将其内容转换为指定类型的对象列表
List<ImportVO> importExcelVOList = ExcelUtils.read(ftFiles.get(0),ImportVO.class);
// 判断导入的数据是否重复
for (int i = 0; i < importExcelVOList.size(); i++) {
ImportVO importVo1 = importExcelVOList.get(i);
for (int j = i + 1; j < importExcelVOList.size(); j++) {
ImportVO importVo2 = importExcelVOList.get(j);
if (importVo1.getName().equals(importVo2.getName()) &&
importVo1.getAge().equals(importVo2.getAge())) {
throw exception(ALL, "第"+(i + 1)+"行和第"+(j + 1)+"行数据重复!");
}
}
}
// 验证导入数据是否已经存在于表中:存在--修改更新该条数据;不存在--直接添加
for (ImportVO importExcelVO : importExcelVOList) {
// 验证点检类别是否存在于基础类别表中
QueryWrapper<studentDO> qw3 = new QueryWrapper<>();
qw3.in("name", importExcelVO.getName());
StudentDO studentDO = studentMapper.selectOne(qw3);
if (studentDO == null) {
// todo 添加数据 mapper.inseert
// 若传入A;B;C列,想存到数据库是[{index:0,value:A},{index:1,value:B},{index:2,value:C}]
String[] optionsArray = importExcelVO.getOptions().split("[;;]");
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < optionsArray.length; i++) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("index", i);
jsonObject.put("value", optionsArray[i]);
jsonArray.add(jsonObject);
}
String jsonArrayString = jsonArray.toJSONString();
projectDO1.setOptions(jsonArrayString);
// Json类型数据存储结束——end———
}else {
// todo 添加数据 mapper.update
}
}
for (MultipartFile ft : files) {
String name = ft.getOriginalFilename();
}
return null;
}