SpringBoot+VUE实现文件导入并将其保存到Liunx系统

简介: 需求: 必须支持PDF、docx、xlsx、xls、doc等格式, 文件上传后保存在本地文件夹, 需要进行在线预览

一、需求

  • 必须支持PDF、docx、xlsx、xls、doc等格式
  • 文件上传后保存在本地文件夹
  • 需要进行在线预览

# 二、前端代码实现

## 2.1 显示实现
首先我们需要添加一个用于操作的按钮上去,像这样的:

<a @click="fileRef.onOpen(record)">查看文件</a>
<a @click="ProfessionImpExpRef.onOpen(record)">上传文件</a>

2.1.1 a标签实现

2.1.1.1 上传标签实现

当用户点击上传文件时我们会在右侧打开一个抽屉,用以展示上传界面,页面部分像这样:

<ProfessionImpExp ref="ProfessionImpExpRef" />

具体逻辑像这样:

//professionImpExp.vue 为上传界面
import ProfessionImpExp from './professionImpExp.vue'
const ProfessionImpExpRef = ref()

2.1.1.2 查看标签实现

文件查看部分基本和上传部分实现类似,页面部分:

<File ref="fileRef" @successful1="table.refresh(true)" />
//file.vue为文件查看界面
import File from "./file.vue";
const fileRef = ref()
const file = ref(null)

## 2.2 上传文件和文件查看界面实现
### 2.2.1 上传文件界面

2.2.1.1 上传文件界面展示部分

当用户点击上传文件时,我们需要打开一个界面用以提示用户支持的类型和上传注意事项、上传结果,像这样的:

<template>
    <xn-form-container title="导入导出" :width="700" :visible="visible" :destroy-on-close="true" @close="onClose">
        <span
            >导入数据格式严格按照要求进行数据录入,<b style="color: red">重复导入或使用重名文件将会覆盖之前数据内容</b>
        </span>
        <a-divider dashed />
        <div>
            <a-spin :spinning="impUploadLoading">
                <a-upload-dragger :show-upload-list="false" :custom-request="customRequestLocal" :accept="uploadAccept">
                    <p class="ant-upload-drag-icon">
                        <inbox-outlined></inbox-outlined>
                    </p>
                    <p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
                    <p class="ant-upload-hint">仅支持PDF、docx、xlsx、xls、doc格式文件</p>
                </a-upload-dragger>
            </a-spin>
        </div>
        <a-alert v-if="impAlertStatus" type="info" :show-icon="false" banner closable @close="onImpClose" class="mt-3">
            <template #description>
                <p>导入完成</p>
            </template>
        </a-alert>
    </xn-form-container>
</template>

展示出来就是下面的效果:
1.png

2.2.1.1 上传文件界面逻辑部分

用户点击后,我们会打开一个抽屉,并将获取到的本行数据id传入到这个界面和上传的数据文件进行绑定,之后传回后端处理。

import { message } from 'ant-design-vue'
    import professionApi from '@/api/biz/professionApi'
    import {cloneDeep} from "lodash-es";
    const impUploadLoading = ref(false)
    const impAlertStatus = ref(false)
    const dataId = ref()
    const impAccept = [
        {
            extension: '.xls',
            mimeType: 'application/vnd.ms-excel'
        },
        {
            extension: '.xlsx',
            mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        },
        {
            extension: '.PDF',
            mimeType: 'application/pdf'
        },
        {
            extension: '.docx',
            mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        },
        {
            extension: '.doc',
            mimeType: 'application/msword'
        },
    ]
    // 指定能选择的文件类型
    const uploadAccept = String(
        impAccept.map((item) => {
            return item.mimeType
        })
    )
    // 导入
    const customRequestLocal = (data) => {
        impUploadLoading.value = true
        // 校验上传文件扩展名和文件类型是否为支持类型
        const extension = '.'.concat(data.file.name.split('.').slice(-1).toString().toLowerCase())
        const mimeType = data.file.type
        // 提取允许的扩展名
        const extensionArr = impAccept.map((item) => item.extension)
        // 提取允许的MIMEType
        const mimeTypeArr = impAccept.map((item) => item.mimeType)
        if (!extensionArr.includes(extension) || !mimeTypeArr.includes(mimeType)) {
            message.warning('上传文件类型仅支持PDF、word、excel、xls、xlsx格式文件!')
            impUploadLoading.value = false
            return false
        }

        const formData = new FormData();
        formData.append("file",data.file)
        formData.append("id",dataId.value.id)
        return professionApi
            .professionImport(formData)
            .then((res) => {
                impAlertStatus.value = res
            })
            .finally(() => {
                impUploadLoading.value = false
            })
    }
    // 关闭导入提示
    const onImpClose = () => {
        impAlertStatus.value = false
    }
    // 定义emit事件
    const emit = defineEmits({ successful: null })
    // 默认是关闭状态
    let visible = ref(false)
    const submitLoading = ref(false)

    // 打开抽屉
    const onOpen = (record) => {
        visible.value = true
        if (record) {
            let recordData = cloneDeep(record)
            dataId.value = Object.assign({}, recordData)
        }
    }
    // 关闭抽屉
    const onClose = () => {
        visible.value = false
        // 关闭导入的提示
        onImpClose()
    }

    // 调用这个函数将子组件的一些数据和方法暴露出去
    defineExpose({
        onOpen
    })

### 2.2.2 查看文件界面
#### 2.2.2.1 查看文件界面展示部分
用户点击查看文件后,进入到这个界面进行文件查看和在线展示。

<template>
    <xn-form-container
        :title="'文件详情'"
        :width="500"
        :visible="visible"
        :destroy-on-close="true"
        @close="onClose"
    >
        <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
            <a-form-item label="文件:" name="url">
                <ol>
                    <li v-for="data in formData">
                        <a :href="'http://view.officeapps.live.com/op/view.aspx?src=https://img.qcybj.com/file/'+data" target="_blank"> {{ data }}</a>
                        
                    </li>
                </ol>
            </a-form-item>
        </a-form>
        <template #footer>
            <a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
        </template>
    </xn-form-container>
</template>

具体的效果类似这种:
2.png

#### 2.2.2.2 查看文件界面逻辑部分
这部分的逻辑很简单,主要就是对后端的数据解析并绑定。

import { cloneDeep } from 'lodash-es'
import XnFormContainer from "@/components/XnFormContainer/index.vue";

// 抽屉状态
const visible = ref(false)
const emit = defineEmits({ successful: null })
const file = ref()
const submitLoading = ref(false)
const formData = ref({})
// 打开抽屉
const onOpen = (record) => {
    visible.value = true
    if (record) {
        let recordData = cloneDeep(record)
        let str = Object.assign({}, recordData).url.substr(1)
        let str1 = str.substring(0,str.length-1)
        formData.value = str1.split(",")
    }
}
// 关闭抽屉
const onClose = () => {
    visible.value = false
}
// 默认要校验的
const formRules = {
}
// 抛出函数
defineExpose({
    onOpen
})

## 2.2 其他逻辑

2.2.1 本行数据id选择逻辑

const selectedRowKeys = ref([])
    // 列表选择配置
    const options = {
        // columns数字类型字段加入 needTotal: true 可以勾选自动算账
        alert: {
            show: true,
            clear: () => {
                selectedRowKeys.value = ref([])
            }
        },
        rowSelection: {
            onChange: (selectedRowKey, selectedRows) => {
                selectedRowKeys.value = selectedRowKey
            }
        }
    }

2.2.2 API 逻辑

这部分内容可以参照我之前的文章,这里不再多说~

    //业务导入
    professionImport(data) {
        return request('import', data)
    },

三、后端实现

后端部分大多分逻辑SpringBoot + Ant Design Vue实现数据导出功能都有提及,这里不再多言。我们之说最重要的实现逻辑:

  @Transactional(rollbackFor = Exception.class)
    @Override
    public String importProfession(MultipartFile file,String id ) throws IOException {
        Profession profession = baseMapper.selectById(id);
        String urlList = profession.getUrl();
        //定义文件名
        String imgName = file.getOriginalFilename();
        //定义上传路径
        String upPath = path + imgName;
        byte[] bytes = new byte[1024];
        int dataLine;
        try(BufferedInputStream bufferedInputStream = new BufferedInputStream(file.getInputStream());
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(upPath))){
            while ((dataLine=bufferedInputStream.read(bytes))!= -1){
                bufferedOutputStream.write(bytes, 0, dataLine);
            }
        }
        if(urlList == null){
            profession.setUrl(imgName);
        }else {
            List<String> list = Arrays.asList(urlList.split(","));
            List<String> arrList = new ArrayList<>(list);
            arrList.add(imgName);
            profession.setUrl(arrList.toString());
        }
        QueryWrapper<Profession> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Profession::getId,id);
        this.update(profession,queryWrapper);
        return imgName;
    }

这里有一点需要注意,Java的IO方法很多,需要注意的是liunx系统中写入要指定绝对路径,不要用相对路径。

比如 MultipartFile 的 transferTo() 方法就可能使用相对路径。一旦使用了相对路径你就会发现原本指定写入的路径前多出了它:

/tmp/tomcat.8080.450079304707479782/work/Tomcat/localhost/ROOT
目录
相关文章
|
9天前
|
存储 前端开发 Java
Springboot静态资源映射及文件映射
在Spring Boot项目中,为了解决前端访问后端存储的图片问题,起初尝试通过静态资源映射实现,但发现这种方式仅能访问打包时已存在的文件。对于动态上传的图片(如头像),需采用资源映射配置,将特定路径映射到服务器上的文件夹,确保新上传的图片能即时访问。例如,通过`addResourceHandler(&quot;/img/**&quot;).addResourceLocations(&quot;file:E:\\myProject\\forum_server\\&quot;)`配置,使前端可通过URL直接访问图片。
Springboot静态资源映射及文件映射
|
8天前
|
前端开发 JavaScript Java
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
53 13
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
|
9天前
|
人工智能 JavaScript 关系型数据库
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
55 14
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
|
7天前
|
SQL JavaScript 安全
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
44 11
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
|
11天前
|
人工智能 JavaScript 安全
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
55 13
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
|
24天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
59 10
|
24天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
43 8
|
24天前
|
JavaScript 搜索推荐 Java
基于SpringBoot+Vue实现的家乡特色推荐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
54 8
|
24天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的高校食堂移动预约点餐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
66 3
|
存储 前端开发 Java
SpringBoot文件上传和下载
SpringBoot文件上传和下载
SpringBoot文件上传和下载

热门文章

最新文章