vue+springboot上传文件、图片、视频及回显到前端详解

Java
357
0
0
2023-05-14
标签   SpringBoot
目录
  • 效果图
  • 设计逻辑
  • 数据库表
  • 前端vue
  • html
  • js代码
  • 前端思路
  • 储存文件信息
  • 上传文件对象
  • 后端上传下载代码
  • 完整代码
  • workinfo.vue
  • SubmitHomeworkController
  • 总结

效果图

预览:

设计逻辑

数据库表

前端vue

html

       <div class="right-pannel">
                    <div class="data-box">
                        <!--上传的作业-->
                        <div style="display: block" id="">
                            <div class="title clearfix">
                                <div class="all fl" data-folderid="0">
                                    <a class="here">上传附件(上传项目演示视频应为mp4格式)</a>
                                </div>
                            </div>
                            <div class="container_con">
                                <!--作业超时提示-->
                                <el-dialog
                                        title="提示"
                                        :visible.sync="workLateTip"
                                        width="30%">
                                    <span>作业已截止,禁止提交,请联系任课老师</span>
                                    <span slot="footer" class="dialog-footer">
                            <el-button @click="workLateTip = false">取 消</el-button>
                            <el-button type="primary" @click="workLateTip = false">确 定</el-button>
                          </span>
                                </el-dialog>
                                <!--展示如下界面-->
                                <div>
                                    <div class="operation" id="submit-display">

                                        <div class="add-resource-btn fl" @click="choiceImg">
                                            <span class="tips"><i class="iconfont"></i>上传文件</span>
                                            <input type="file" name="file" class="webuploader-element-invisible"
                                                   @change="getFile" ref="filElem" id="submitFile">
                                        </div>

                                        <div class="multidelete fl" style="display: none;" id="piliang-delete"
                                             @click="deleteZiYuan"><i
                                                class="iconfont iconshanchu1"></i>批量删除
                                        </div>
                                    </div>

                                    <el-progress id="showProgress" style="display:none;" :stroke-width="16"
                                                 :percentage="progressPercent"></el-progress>

                                    <el-table
                                            ref="multipleTable"
                                            :data="tableFileList"
                                            tooltip-effect="dark"
                                            style="width: 100%"
                                            @selection-change="handleSelectionChange">
                                        <el-table-column
                                                type="selection"
                                                width="55">
                                        </el-table-column>
                                        <el-table-column
                                                prop="submitHomeworkFileName"
                                                label="文件名"
                                                width="350">
                                        </el-table-column>
                                        <el-table-column
                                                prop="submitHomeworkFileSize"
                                                label="大小"
                                                width="150">
                                        </el-table-column>
                                        <el-table-column
                                                prop="submitHomeworkGrade"
                                                label="成绩状态"
                                                width="100">
                                        </el-table-column>

                                        <el-table-column
                                                prop="submitHomeworkCreateTime"
                                                label="上传时间"
                                                width="220">
                                        </el-table-column>

                                        <el-table-column
                                                width="300">
                                            <template slot-scope="scope">
                                                <a @click="preview(scope.row.submitHomeworkFilePath)"
                                                   class="homework-operation"
                                                   style="margin-left: 50px">预览</a>
                                                <a class="homework-operation"
                                                   @click="saveFile(scope.row.submitHomeworkId)">下载</a>
                                                <a @click="deleteOne(scope.row.submitHomeworkId)"
                                                   class="homework-operation">删除</a>
                                            </template>
                                        </el-table-column>
                                    </el-table>
                                </div>
                            </div>

                        </div>
                    </div>
                </div>

js代码

 //上传本地文件
            choiceImg() {
                this.$refs.filElem.dispatchEvent(new MouseEvent('click'))
            },


            getFile() {
                const inputFile = this.$refs.filElem.files[0];
                //如果大于1G,提示用户
                if (inputFile.size > 1048576000) {
                    this.$message({
                        message: '上传文件应小于1G',
                        type: 'error',
                        duration: 3000
                    });
                    return
                }
                //初始化为0,表示不是项目介绍视频
                this.submitWork.submitHomeworkIntroduceVideo = "0"
                // console.log(inputFile)
                //视频类型:video/mp4
                if (inputFile.type === "video/mp4") {
                    this.$message({
                        message: '上传视频将作为视频介绍',
                        type: 'info',
                        duration: 5000
                    });
                    //设置 1,表示标记为项目介绍视频
                    this.submitWork.submitHomeworkIntroduceVideo = "1"

                }
                let fileSize = inputFile.size / 1000;
                let finalSize = 0;
                if (fileSize > 1000) {
                    finalSize = fileSize / 1000;
                    this.fileSizeType = "MB"
                } else {
                    finalSize = fileSize;
                    this.fileSizeType = "KB"
                }
                this.tempFileSize = finalSize;
                this.fileName = inputFile.fileName

                this.upload()
            },
            //上传一个新的资源
            upload() {
                this.submitWork.homeworkId = sessionStorage.getItem("homeworkId")
                this.submitWork.studentId = sessionStorage.getItem("studentId")
                this.submitWork.submitHomeworkFileSize = this.tempFileSize + "" + this.fileSizeType
                // console.log(this.submitWork)
                homeworkApi.submitHomework(this.submitWork)
                    .then(res => {
                        this.$message({
                            message: '作业信息提交成功',
                            type: 'success'
                        });
                        this.addZiYuanDis = false;
                        //提交作业的id存储在会话中
                        sessionStorage.setItem("finishWorkId", res.data.submitWork.submitHomeworkId)
                        //当已经存进数据库之后再进行修改
                        this.submit();
                    }).catch(
                    () => {
                        this.$message({
                            message: '作业信息提交失败!请重试!',
                            type: 'error'
                        });
                    }
                )

            },

            //文件提交到本地云端存储
            submit() {
                var formData = new FormData();
                const submitHomeworkId = sessionStorage.getItem("finishWorkId")
                let file = this.$refs.filElem.files[0]
                formData.append('file', file) // 'file' 这个名字要和后台获取文件的名字一样;

                //显示进度条
                document.getElementById("showProgress").style.display = "block";
                document.getElementById("submit-display").style.display = "none";

                let configs = {
                    headers: {
                        'Content-Type': 'multipart/form-data',
                        token: sessionStorage.getItem("token")
                    },
                    onUploadProgress: (progressEvent) => {
                        if (progressEvent.lengthComputable) {   //是否存在进度
                            this.progressPercent = parseInt((progressEvent.loaded / progressEvent.total) * 100)
                        }
                    },
                }
                this.$axios.post('submitHomework/submitHomeworkFile/' + submitHomeworkId, formData, configs)
                    .then(
                        res => {
                            this.$message({
                                message: '作业上传成功',
                                type: 'success'
                            });
                            document.getElementById("showProgress").style.display = "none";
                            document.getElementById("submit-display").style.display = "block";
                            this.getAllZiYuan();

                        }).catch(error => {
                    this.$message({
                        message: '作业上传失败!请重试!',
                        type: 'error'
                    });
                    document.getElementById("showProgress").style.display = "none";
                    document.getElementById("submit-display").style.display = "block";
                })

            },

前端思路

分成两部,1.通过前端将文件的基本信息传送到后端进行储存,返回已储存的文件id,2.再将文件发送到后端储存。

储存文件信息

上传文件对象

后端上传下载代码

  @RequestMapping("/submitHomeworkFile/{submitHomeworkId}")
    public R submitHomeworkFile(@RequestParam("file") MultipartFile multipartFile, @PathVariable long submitHomeworkId, HttpServletRequest req) throws IOException {
        System.out.println("id___________________"+submitHomeworkId);
        SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
        String format = sdf.format(new Date());//时间

//       获得项目在磁盘的地址,如:D:/eclipse-workspace/studyProject/youketangV0.0/youketang_ssm/target/classes//store/2023/02/19/
//        String realPath = ResourceUtils.getURL("classpath:").getPath() + "/store" + format;
//        /www/wwwroot/resource
        String realPath = "D:" + "/store" + format;
//        String realPath = "/www/wwwroot/resource" + "/store" + format;
// String realPath = req.getServletContext().getRealPath("/")+"/store"+format;
// getRealPath("/")方法返回的是项目在服务器的绝对路径(C:\Users\29395\AppData\Local\Temp\tomcat-docbase.4782946598994668439.8888\/store/2023/02/19/)
//由于是在temp临时文件,每次重启服务器,都找不到之前的文件url.

        File fileDir = new File(realPath);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        if (multipartFile != null) {
            String fileName = multipartFile.getOriginalFilename();//获取名字
//            172.17.160.1为服务器的IP地址
//            String url = req.getScheme() + "://" + "47.94.255.44" + ":" + req.getServerPort() + "/store" + format + fileName;
            String url = req.getScheme() + "://" + "localhost" + ":" + req.getServerPort() + "/store" + format + fileName;
//          transferTo(File dest) 将接收到的文件传输到给定的目标文件。
            multipartFile.transferTo(new File(realPath, fileName));

            String fileReal = fileDir + "//" + fileName;
//            System.out.println(fileReal);
            SubmitHomework submitHomework = submitHomeworkService.findSubmitHomeworkById(submitHomeworkId);
            submitHomework.setSubmitHomeworkFileRealPath(fileReal);
            submitHomework.setSubmitHomeworkFilePath(url);
            submitHomework.setSubmitHomeworkFileName(multipartFile.getOriginalFilename());
            submitHomeworkService.modifySubmitHomework(submitHomework);

            return R.ok().data("path", url);
        } else {
            return R.ok().message("请选中文件");
        }
    }

    @GetMapping("/downloadSubmitHomeworkFile/{submitHomeworkId}")
    public void downloadSubmitHomeworkFile(@PathVariable("submitHomeworkId") long submitHomeworkId,
                         HttpServletResponse response) {
        SubmitHomework submitHomework = submitHomeworkService.findSubmitHomeworkById(submitHomeworkId);
        String fileRealPath = submitHomework.getSubmitHomeworkFileRealPath();
        String fileName = submitHomework.getSubmitHomeworkFileName();
        File file = new File(fileRealPath);
        byte[] buffer = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            //文件是否存在
            if (file.exists()) {
                response.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有
                //设置响应
                response.setContentType("application/octet-stream;charset=UTF-8");
                // 将响应头中的Content-Disposition暴露出来,不然前端获取不到
                response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
                // 在响应头中的Content-Disposition里设置文件名称
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//                response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
                os = response.getOutputStream();
                bis = new BufferedInputStream(new FileInputStream(file));
                while (bis.read(buffer) != -1) {
                    os.write(buffer);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (os != null) {
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

这个我放在d盘下面,需要修改映射路径

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //   访问相对路径
        // PS:注意文件路径最后的斜杠(文件分隔符),如果缺少了,就不能够正确的映射到相应的目录
        String baseDocumentPath = "file:D:/document/";
        String baseStorePath = "file:D:/store/";
//        String baseDocumentPath = "file:/www/wwwroot/resource/document/";
//        String baseStorePath = "file:/www/wwwroot/resource/store/";
        //        /www/wwwroot/resource
        registry.addResourceHandler("/document/**").addResourceLocations(baseDocumentPath);
        registry.addResourceHandler("/store/**").addResourceLocations(baseStorePath);
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }

完整代码

workinfo.vue

<template>
    <div>
        <!--头部-->
        <div class="header">
            <div class="header-left">
        <span class="header-icon" @click="jumpToHomework"><i class="iconfont iconfanhui"
                                                             style="font-size:38px;color:#5F6368;"></i></span>
                <span class="courseName" @click="jumpToHomework">{{ courseName }}</span>
            </div>
            <div class="header-center">
                <span style="border-bottom: 4px solid #2C58AB;">提交作业</span>
            </div>
            <div class="header-right">
                <ul class="nav-menu-right">
                </ul>
            </div>
        </div>


        <div class="data-page cWidth-new" style="width: 81%; padding: 0;">
            <div class="resources-area">

                <div class="right-pannel">
                    <div class="introduce" style=" height: 55px;  line-height: 55px;  border-radius: 8px 8px 0 0;  background: #F1F3F4;padding-left: 15px;
"> 有关作业的基本信息
                    </div>

                    <!--在这里加入一个表单-->
                    <el-form :model="homeworkForm" ref="homeworkForm"
                             class="demo-dynamic" :rules="rules"
                             label-width="80px" style="margin-top: 30px;">
                        <el-form-item prop="title"
                                      label="作业题目" style="color: #34373D;">
                            <el-input v-model="homeworkForm.homeworkTitle" disabled></el-input>
                        </el-form-item>

                        <el-form-item prop="fullScore"
                                      label="分数">
                            <el-input v-model="homeworkForm.homeworkFullScore" disabled></el-input>
                        </el-form-item>

                        <el-form-item prop="deadline"
                                      label="截止日期">
                            <el-input style="color: black" v-model="homeworkForm.homeworkDeadline" disabled></el-input>
                        </el-form-item>

                        <el-form-item prop="description"
                                      label="作业描述">
                            <!--渲染-->
                            <span> <p v-html="homeworkForm.homeworkDescription"></p></span>
                        </el-form-item>
                    </el-form>
                </div>


                <div class="right-pannel">
                    <div class="introduce" style=" height: 55px;  line-height: 55px;  border-radius: 8px 8px 0 0;  background: #F1F3F4;padding-left: 15px;
"> 项目相关介绍
                    </div>

                    <!--                在这里加入一个表单-->
                    <el-form :model="dynamicValidateForm" ref="dynamicValidateForm"
                             class="demo-dynamic" :rules="rules"
                             label-width="80px" style="margin-top: 30px;">
                        <el-form-item prop="projectHomeworkName"
                                      label="项目名称">
                            <el-input v-model="dynamicValidateForm.projectHomeworkName"></el-input>
                        </el-form-item>
                        <el-form-item prop="projectHomeworkIntroduceText"
                                      label="项目介绍">
                            <el-input v-model="dynamicValidateForm.projectHomeworkIntroduceText"></el-input>
                        </el-form-item>

                        <el-form-item prop="projectHomeworkTeamNumber"
                                      label="小组成员">
                            <el-input v-model="dynamicValidateForm.projectHomeworkTeamNumber"></el-input>
                        </el-form-item>

                        <el-form-item>
                            <el-button type="primary" @click="submitForm('dynamicValidateForm')" v-preventReClick>提交
                            </el-button>
                            <el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
                        </el-form-item>
                    </el-form>
                </div>

                <div style="display: none" id="video">
                    <video
                            id="my-video"
                            class="video-js"
                            controls
                            preload="auto"
                            width="1152"
                            height="680"
                            data-setup="{}"
                            :src=vedioSrc>
                    </video>
                </div>

                <div class="right-pannel">
                    <div class="data-box">
                        <!--上传的作业-->
                        <div style="display: block" id="">
                            <div class="title clearfix">
                                <div class="all fl" data-folderid="0">
                                    <a class="here">上传附件(上传项目演示视频应为mp4格式)</a>
                                </div>
                            </div>
                            <div class="container_con">
                                <!--作业超时提示-->
                                <el-dialog
                                        title="提示"
                                        :visible.sync="workLateTip"
                                        width="30%">
                                    <span>作业已截止,禁止提交,请联系任课老师</span>
                                    <span slot="footer" class="dialog-footer">
                            <el-button @click="workLateTip = false">取 消</el-button>
                            <el-button type="primary" @click="workLateTip = false">确 定</el-button>
                          </span>
                                </el-dialog>
                                <!--展示如下界面-->
                                <div>
                                    <div class="operation" id="submit-display">

                                        <div class="add-resource-btn fl" @click="choiceImg">
                                            <span class="tips"><i class="iconfont"></i>上传文件</span>
                                            <input type="file" name="file" class="webuploader-element-invisible"
                                                   @change="getFile" ref="filElem" id="submitFile">
                                        </div>

                                        <div class="multidelete fl" style="display: none;" id="piliang-delete"
                                             @click="deleteZiYuan"><i
                                                class="iconfont iconshanchu1"></i>批量删除
                                        </div>
                                    </div>

                                    <el-progress id="showProgress" style="display:none;" :stroke-width="16"
                                                 :percentage="progressPercent"></el-progress>

                                    <el-table
                                            ref="multipleTable"
                                            :data="tableFileList"
                                            tooltip-effect="dark"
                                            style="width: 100%"
                                            @selection-change="handleSelectionChange">
                                        <el-table-column
                                                type="selection"
                                                width="55">
                                        </el-table-column>
                                        <el-table-column
                                                prop="submitHomeworkFileName"
                                                label="文件名"
                                                width="350">
                                        </el-table-column>
                                        <el-table-column
                                                prop="submitHomeworkFileSize"
                                                label="大小"
                                                width="150">
                                        </el-table-column>
                                        <el-table-column
                                                prop="submitHomeworkGrade"
                                                label="成绩状态"
                                                width="100">
                                        </el-table-column>

                                        <el-table-column
                                                prop="submitHomeworkCreateTime"
                                                label="上传时间"
                                                width="220">
                                        </el-table-column>

                                        <el-table-column
                                                width="300">
                                            <template slot-scope="scope">
                                                <a @click="preview(scope.row.submitHomeworkFilePath)"
                                                   class="homework-operation"
                                                   style="margin-left: 50px">预览</a>
                                                <a class="homework-operation"
                                                   @click="saveFile(scope.row.submitHomeworkId)">下载</a>
                                                <a @click="deleteOne(scope.row.submitHomeworkId)"
                                                   class="homework-operation">删除</a>
                                            </template>
                                        </el-table-column>
                                    </el-table>
                                </div>
                            </div>

                        </div>
                    </div>
                </div>

            </div>
        </div>


    </div>

</template>

<script>
    import homeworkApi from "@/api/homework";

    var formData = new window.FormData() // vue 中使用此方法创建FromData对象 window.FormData(),否则会报 'FormData isn't definded'
    export default {
        data() {
            var validateName = (rule, value, callback) => {
                if (!value) {
                    return callback(new Error("项目名称不能为空"));
                } else {
                    callback();
                }
            };
            var validateTeamNumber = (rule, value, callback) => {
                if (!value) {
                    return callback(new Error("小组成员不能为空"));
                } else {
                    callback();
                }
            };
            var validateIntroduce = (rule, value, callback) => {
                if (!value) {
                    return callback(new Error("项目介绍不能为空"));
                } else {
                    callback();
                }
            };
            return {

                vedioSrc: '',//项目视频的src


                finishWorkId: '',     //用于更新提交时传递到后台覆盖原纪录
                isLiuYanEmpty: true,       //留言是否为空,默认都是空
                isUpload: false,   //是否提交了该作业
                workLateTip: false,        //作业提交超时提醒
                fileSize: [],     //上传的文件大小
                readWorkTipDisplay: false,      //定义批阅作业的提醒弹框
                tableData: [],      //定义作业提交详情总览
                introduceVideo: '', //标记是否为视频
                input1: '',
                hide: '',
                gradeList: [],
                similarityList: [],
                submitList: [],
                shareList: [],
                selected: false,
                givePoints: '',

                managecheck: false,
                courseName: sessionStorage.getItem("courseName"),
                homeworkId: '',
                submitWorkId: '',//提交作业后端返回的id
                course: {
                    id: '',
                    courseName: '',
                    className: '',
                    year: '',
                    semester: ''
                },
                homework: {},
                classmateCount: '',
                submitCount: '',
                submittedList: [],            //定义提交详情所有学生的信息展示 包括 已批 未批 未交
                submitInfo: {
                    score: '',
                    id: '',
                    name: '',
                    number: '',
                    bestScore: '',
                    publishTime: '',
                    fileAddress: ''
                },
                submitWork: {},
                read: '未阅',
                score: '',
                beginScore: [],
                state: '',

                tempFileSize: '',         //暂时存的文件大小
                fileSizeType: '',        //文件大小类型 MB KB
                fileName: '',

                multipleSelection: [],//选中的文件
                addZiYuanDis: false,
                tableFileList: [],
                deleteIdList: [],               //每次删除完以后记得赋空值


                dynamicValidateForm: {
                    projectHomeworkName: '',
                    projectHomeworkIntroduceText: '',
                    projectHomeworkTeamNumber: ''
                },
                homeworkForm: {
                    title: '',
                    description: '',
                    fullScore: '',
                    deadline: ''
                },
                rules: {
                    projectHomeworkName: [{validator: validateName, trigger: 'blur'}],
                    projectHomeworkTeamNumber: [{validator: validateTeamNumber, trigger: 'blur'}],
                    projectHomeworkIntroduceText: [{validator: validateIntroduce, trigger: 'blur'}],
                },

                dialogImageUrl: '',
                dialogVisible: false,

                progressPercent: 0
            }
        },
        //进入页面内容全部渲染完成后自动引函数
        mounted() {

            this.getProjectHomeworkInfo();
            this.getAllZiYuan();
        },
        methods: {
            getProjectHomeworkInfo() {
                let homeworkId = sessionStorage.getItem("homeworkId");
                let studentId = sessionStorage.getItem("studentId");
                //获取作业的基本信息
                homeworkApi.getHomeworkById(homeworkId).then(
                    res => {
                        // console.log(res.data)
                        this.homeworkForm = res.data.homework
                    }
                )
                homeworkApi.getProjectHomeworkInfo(homeworkId, studentId).then(res => {
                    this.dynamicValidateForm.projectHomeworkIntroduceText = res.data.projectHomework.projectHomeworkIntroduceText
                    this.dynamicValidateForm.projectHomeworkTeamNumber = res.data.projectHomework.projectHomeworkTeamNumber
                    this.dynamicValidateForm.projectHomeworkName = res.data.projectHomework.projectHomeworkName
                })

            },
            //获取所有资源
            getAllZiYuan() {
                let homeworkId = sessionStorage.getItem("homeworkId");
                let studentId = sessionStorage.getItem("studentId");
                homeworkApi.getSubmitHomework(homeworkId, studentId).then(res => {
                    //赋值给文件表格
                    this.tableFileList = res.data.submitHomeworkList
                    //对项目视频介绍标记,判断introduceVideo是否为1,如果为1,则为视频介绍,赋值videoSrc,并显示视频标签.
                    for (var i = 0; i < this.tableFileList.length; i++) {
                        if (this.tableFileList[i].introduceVideo === 1) {
                            this.vedioSrc = this.tableFileList[i].filePath;
                            document.getElementById("video").style.display = "block";
                        }
                    }
                })

            },


            //学生端预览文件
            preview(url) {
                //console.log(indexurl);
                //要预览文件的访问地址
                window.open(url);
            },
            //单个删除
            deleteOne(id) {
                console.log(id)
                this.deleteIdList.push(id)
                this.$confirm('此操作将删除该资料, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    //异步请求删除
                    homeworkApi.removeSubmitHomework(this.deleteIdList)
                        .then(res => {
                            this.deleteIdList = []             //进行置空
                            this.$message({
                                message: '删除成功',
                                type: 'success'
                            });
                            this.getAllZiYuan()
                        })
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },
            //删除资源(点击批量删除)
            deleteZiYuan() {
                let list = this.multipleSelection;
                for (let i = 0; i < list.length; i++) {
                    this.deleteIdList.push(list[i].id);
                }

                this.$confirm('此操作将删除该资料, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    //异步请求删除
                    homeworkApi.removeSubmitHomework(this.deleteIdList)
                        .then(res => {
                            this.deleteIdList = []             //进行置空
                            this.$message({
                                message: '删除成功',
                                type: 'success'
                            });
                            //重新加载界面
                            this.$router.go(0)
                        })
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },
            handleEdit(index, row) {
                console.log(index, row);
            },
            handleSelectionChange(val) {
                //console.log("选中值发生了改变")
                this.multipleSelection = val;
                if (this.multipleSelection.length !== 0) {
                    document.getElementById("piliang-delete").style.display = "block";
                } else {
                    document.getElementById("piliang-delete").style.display = "none";
                }

            },

            //上传本地文件
            choiceImg() {
                this.$refs.filElem.dispatchEvent(new MouseEvent('click'))
            },


            getFile() {
                const inputFile = this.$refs.filElem.files[0];
                //如果大于1G,提示用户
                if (inputFile.size > 1048576000) {
                    this.$message({
                        message: '上传文件应小于1G',
                        type: 'error',
                        duration: 3000
                    });
                    return
                }
                //初始化为0,表示不是项目介绍视频
                this.submitWork.submitHomeworkIntroduceVideo = "0"
                // console.log(inputFile)
                //视频类型:video/mp4
                if (inputFile.type === "video/mp4") {
                    this.$message({
                        message: '上传视频将作为视频介绍',
                        type: 'info',
                        duration: 5000
                    });
                    //设置 1,表示标记为项目介绍视频
                    this.submitWork.submitHomeworkIntroduceVideo = "1"

                }
                let fileSize = inputFile.size / 1000;
                let finalSize = 0;
                if (fileSize > 1000) {
                    finalSize = fileSize / 1000;
                    this.fileSizeType = "MB"
                } else {
                    finalSize = fileSize;
                    this.fileSizeType = "KB"
                }
                this.tempFileSize = finalSize;
                this.fileName = inputFile.fileName

                this.upload()
            },
            //上传一个新的资源
            upload() {
                this.submitWork.homeworkId = sessionStorage.getItem("homeworkId")
                this.submitWork.studentId = sessionStorage.getItem("studentId")
                this.submitWork.submitHomeworkFileSize = this.tempFileSize + "" + this.fileSizeType
                // console.log(this.submitWork)
                homeworkApi.submitHomework(this.submitWork)
                    .then(res => {
                        this.$message({
                            message: '作业信息提交成功',
                            type: 'success'
                        });
                        this.addZiYuanDis = false;
                        //提交作业的id存储在会话中
                        sessionStorage.setItem("finishWorkId", res.data.submitWork.submitHomeworkId)
                        //当已经存进数据库之后再进行修改
                        this.submit();
                    }).catch(
                    () => {
                        this.$message({
                            message: '作业信息提交失败!请重试!',
                            type: 'error'
                        });
                    }
                )

            },

            //文件提交到本地云端存储
            submit() {
                var formData = new FormData();
                const submitHomeworkId = sessionStorage.getItem("finishWorkId")
                let file = this.$refs.filElem.files[0]
                formData.append('file', file) // 'file' 这个名字要和后台获取文件的名字一样;

                //显示进度条
                document.getElementById("showProgress").style.display = "block";
                document.getElementById("submit-display").style.display = "none";

                let configs = {
                    headers: {
                        'Content-Type': 'multipart/form-data',
                        token: sessionStorage.getItem("token")
                    },
                    onUploadProgress: (progressEvent) => {
                        if (progressEvent.lengthComputable) {   //是否存在进度
                            this.progressPercent = parseInt((progressEvent.loaded / progressEvent.total) * 100)
                        }
                    },
                }
                this.$axios.post('submitHomework/submitHomeworkFile/' + submitHomeworkId, formData, configs)
                    .then(
                        res => {
                            this.$message({
                                message: '作业上传成功',
                                type: 'success'
                            });
                            document.getElementById("showProgress").style.display = "none";
                            document.getElementById("submit-display").style.display = "block";
                            this.getAllZiYuan();

                        }).catch(error => {
                    this.$message({
                        message: '作业上传失败!请重试!',
                        type: 'error'
                    });
                    document.getElementById("showProgress").style.display = "none";
                    document.getElementById("submit-display").style.display = "block";
                })

            },
            //跳转到作业
            jumpToHomework() {
                sessionStorage.setItem("homeworkId", '');
                this.$router.push({name: 'SHomework'});
            },
            saveFile(submitHomeworkId) {
                this.$axios.get('submitHomework/downloadSubmitHomeworkFile/' + submitHomeworkId,
                    {
                        responseType: 'blob'
                        , headers:
                            {
                                'token':
                                    sessionStorage.getItem("token")
                            }
                    })
                    .then((res) => {
                        // console.log('文件下载成功');
                        const blob = new Blob([res.data]);
                        // 获取文件名称, res.headers['content-disposition']:  attachment;filename=???????.docx
                        const fileNameUtf8 = res.headers['content-disposition'].split(";")[1].split("filename=")[1];
                        //%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E8%AE%A1%E5%88%92%E8%A1%A8.docx  解码后:软件项目计划表.docx
                        var fileName = decodeURIComponent(fileNameUtf8)
                        console.log("res:" + res.headers['content-disposition'])
                        console.log("fileName:" + fileName)
                        //对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
                        //IE10以上支持blob,但是依然不支持download
                        //支持a标签download的浏览器
                        const link = document.createElement('a');//创建a标签
                        link.download = fileName;//a标签添加属性
                        link.style.display = 'none';
                        link.href = URL.createObjectURL(blob);
                        document.body.appendChild(link);
                        link.click();//执行下载
                        URL.revokeObjectURL(link.href); //释放url
                        document.body.removeChild(link);//释放标签
                        this.$message.success("作业下载成功!")
                    }).catch((res) => {
                    this.$message.error("作业下载失败!请重试!")
                });

            },


            //提交表单
            submitForm(formName) {
                //进行校验
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        let homeworkId = sessionStorage.getItem("homeworkId")
                        let studentId = sessionStorage.getItem("studentId")
                        let projectData = {
                            homeworkId: homeworkId,
                            studentId: studentId,
                            projectHomeworkTeamNumber: this.dynamicValidateForm.projectHomeworkTeamNumber,
                            projectHomeworkIntroduceText: this.dynamicValidateForm.projectHomeworkIntroduceText,
                            projectHomeworkName: this.dynamicValidateForm.projectHomeworkName
                        }
                        homeworkApi.saveProjectHomework(projectData)
                            .then(res => {
                                this.$message({
                                    message: '提交成功',
                                    type: 'success'
                                });
                                this.dynamicValidateForm.projectHomeworkTeamNumber = res.data.projectHomework.projectHomeworkTeamNumber
                                this.dynamicValidateForm.projectHomeworkIntroduceText = res.data.projectHomework.projectHomeworkIntroduceText
                                this.dynamicValidateForm.projectHomeworkName = res.data.projectHomework.projectHomeworkName
                            })

                    } else {
                        this.$message({
                            message: '请检查格式,再提交!',
                            type: 'error'
                        });
                    }
                });
            },

            //重制表单
            resetForm(formName) {
                this.$refs[formName].resetFields();
                this.dynamicValidateForm.projectHomeworkName = ""
                this.dynamicValidateForm.projectHomeworkIntroduceText = ""
                this.dynamicValidateForm.projectHomeworkTeamNumber = ""
            },

        }
    }
</script>

<style scoped src="../../assets/discuss_css/coursewarev3.css"></style>
<style scoped>

    a {
        text-decoration: none;
    }

    li {
        list-style-type: none;
    }

    .right-pannel .operation {
        padding: 24px 24px 0;
        height: 42px;
    }

    .right-pannel .operation > div {
        width: 130px;
        height: 40px;
        line-height: 40px;
        color: #32BAF0;
        border: 1px solid #32BAF0;
        border-radius: 4px;
        padding-left: 22px;
        margin-right: 15px;
        cursor: pointer;
    }

    .fl {
        float: left;
    }

    .right-pannel .operation div i {
        font-size: 14px;
        padding-right: 10px;
    }

    .homework-operation {
        color: #4d90fe;
        font-size: 10px;
        margin-left: 20px;
        cursor: pointer;
    }

</style>
<style scoped>
    @import url('../../assets/file/iconfont.css');

    .header {
        box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.04);
        background: none repeat scroll 0% 0% #fff;
        display: flex;
        justify-content: space-between;
        margin-top: 20px;
        height: 45px;
    }

    .header-icon {
        cursor: pointer;
    }

    .courseName {
        background: #2c58ab;
        color: white;
        padding: 6px 20px;
        border-radius: 16px;
        font-size: 14px;
        font-family: PingFangSC-Medium;
        font-weight: 500;
        position: relative;
        bottom: 16px;
        right: 45px;
    }

    .header-left {
        position: relative;
        left: 50px;
    }

    .header-right {
        position: relative;
        right: 100px;

    }

    .header-center span {
        height: 74px;
        padding-left: 50px;
        padding-right: 50px;
        font-size: 16px;
        font-weight: 500;
        color: rgba(59, 61, 69, 1);
        padding-bottom: 20px;
        cursor: pointer;

    }

    .header-center span:hover {
        border-bottom: 4px solid #2C58AB;
    }

    .head-title h2 {
        font-size: 18px;
        color: #2d2d2d;
        font-weight: 400;
        display: inline-block;
    }

    .head-title .togsh p {
        padding: 5px 20px;
        margin-right: 10px;
        background: rgba(0, 0, 0, .1);
    }

    .head-title .togsh p {
        padding: 5px 20px;
        margin-right: 10px;
        background: rgba(0, 0, 0, .1);
        font-size: 14px;
        width: 175px;
        margin-top: -5px;
    }

    .classify dt {
        color: #5A5A5A;
        line-height: 46px;
        height: 46px;
        width: 150px;
        border-right: 1px solid #DCDCDC;
        background: #F2F2F2;
        text-indent: 30px;
        font-size: 12px;
        margin-right: 36px;
        border-bottom: 1px dashed #eaeaea;
        margin-bottom: -1px;
    }

    .classify li {
        width: 48px;
        height: 20px;
        line-height: 20px;
        margin-right: 30px;
        border: 1px solid transparent;
        cursor: pointer;
        font-size: 12px;
        text-align: center;
    }

    .classify el-checkbox {
        padding-left: 25px;
        font-size: 12px;
        color: #5a5a5a;
        border-radius: 3px;
        height: 33px;
        line-height: 33px;
        width: 83px;
        cursor: pointer;
    }

    li {
        list-style: none;
    }

    .typehead li {
        display: inline-block;
        float: left;
        vertical-align: middle;
    }

    .typehead li div {
        display: block;
        width: 100px;
        line-height: 38px;
        border: 1px solid transparent;
        margin-left: -1px;
        color: #595959;
        font-size: 12px;
    }


    .backwork /deep/ span {
        position: relative;
        bottom: 3px;
        right: 4px;
        font-size: 12px;
    }

    .nav-menu-right {
        float: right;
        margin-right: 65px;
        margin-top: -4px;
    }


    .iconfont {
        font-family: iconfont !important;
        font-size: 16px;
        font-style: normal;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    .cWidth-new {
        width: 1224px;
        margin-left: auto;
        margin-right: auto;
    }

    .cWidth-new {
        width: 1224px;
        margin-left: auto;
        margin-right: auto;
    }

    .clearfix {
        zoom: 1;
    }

</style>

SubmitHomeworkController

package com.wang.youketang.controller;


import com.wang.youketang.common.result.R;
import com.wang.youketang.entity.SubmitHomework;
import com.wang.youketang.service.SubmitHomeworkService;
import io.swagger.annotations.ApiOperation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * (SubmitHomework)表控制层
 */
@RestController
@RequestMapping("/submitHomework")
@CrossOrigin
public class SubmitHomeworkController {
    /**
     * 服务对象
     */
    @Resource
    private SubmitHomeworkService submitHomeworkService;

    //根据课程号和人员id获取交的作业
    @GetMapping("/getSubmitHomework")
    public R getSubmitHomework(@RequestParam long homeworkId, @RequestParam long studentId) {
        List<SubmitHomework> submitHomeWork = submitHomeworkService.selectHWByIds(homeworkId, studentId);
        return R.ok().data("submitHomeworkList", submitHomeWork);
    }


    //    @ApiOperation(value = "提交作业")
    @PostMapping("/submitHomework")
    public R submitHomework(@RequestBody SubmitHomework submitHomework) {
        SubmitHomework submitWork = submitHomeworkService.increaseSubmitHomework(submitHomework);
        return R.ok().data("submitWork", submitWork);
    }

    //    @ApiOperation(value = "根据课程号和用户id获取交的所有作业")
    @GetMapping("/getSubmitHomeworkList")
    public R getSubmitHomeworkList(@RequestParam long courseId, @RequestParam long studentId) {
        List<SubmitHomework> submitHomeworkList = submitHomeworkService.getSubmitHomeworkList(courseId, studentId);
        return R.ok().data("submitHomeworkList", submitHomeworkList);
    }

    //    删除
    @PostMapping("/removeSubmitHomework")
    @Transactional
    public R removeSubmitHomework(@RequestBody long[] submitHomeworkIds) {
        boolean removeResult = false;
        for (long submitHomeworkId : submitHomeworkIds) {
            //通过id获取文件的物理地址,并对其删除。
            // 将"\"替换成"/",java将“\”当成转义符。转化为:“C:/Users/29395/AppData/Local/...”
            String filePath = this.submitHomeworkService.findFileRealPathById(submitHomeworkId);
            if(filePath == null){
//               当路径为空
                removeResult = submitHomeworkService.dropSubmitHomeworkById(submitHomeworkId);
            }else{
//                不为空的时候
                File file = new File(filePath.replace("\\", "/"));
                removeResult =  submitHomeworkService.dropSubmitHomeworkById(submitHomeworkId) && file.delete() ;
            }
        }
        return removeResult ? R.ok() : R.error().message("删除失败!若视频为项目介绍,请先上传新的视频,才能删除旧视频。");
    }

    //  根据id获取提交的作业打分
    @PostMapping("/markSubmitHomework")
    public R markSubmitHomework(@RequestParam long studentId, @RequestParam String grade) {
       boolean updateResult =  submitHomeworkService.modifyGradeByStudentId(studentId,grade);
        return updateResult?R.ok():R.error().message("打分失败!!!");
    }

//   "打回作业"
    @PostMapping("/backSubmitHomework/{studentId}")
    public R backSubmitHomework(@PathVariable long studentId) {
        boolean updateResult = submitHomeworkService.modifyGradeBackByStudentId(studentId);
        return updateResult?R.ok():R.error().message("打回作业失败!!!");
    }


    @RequestMapping("/submitHomeworkFile/{submitHomeworkId}")
    public R submitHomeworkFile(@RequestParam("file") MultipartFile multipartFile, @PathVariable long submitHomeworkId, HttpServletRequest req) throws IOException {
        System.out.println("id___________________"+submitHomeworkId);
        SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
        String format = sdf.format(new Date());//时间

//       获得项目在磁盘的地址,如:D:/eclipse-workspace/studyProject/youketangV0.0/youketang_ssm/target/classes//store/2023/02/19/
//        String realPath = ResourceUtils.getURL("classpath:").getPath() + "/store" + format;
//        /www/wwwroot/resource
        String realPath = "D:" + "/store" + format;
//        String realPath = "/www/wwwroot/resource" + "/store" + format;
// String realPath = req.getServletContext().getRealPath("/")+"/store"+format;
// getRealPath("/")方法返回的是项目在服务器的绝对路径(C:\Users\29395\AppData\Local\Temp\tomcat-docbase.4782946598994668439.8888\/store/2023/02/19/)
//由于是在temp临时文件,每次重启服务器,都找不到之前的文件url.

        File fileDir = new File(realPath);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        if (multipartFile != null) {
            String fileName = multipartFile.getOriginalFilename();//获取名字
//            172.17.160.1为服务器的IP地址
//            String url = req.getScheme() + "://" + "47.94.255.44" + ":" + req.getServerPort() + "/store" + format + fileName;
            String url = req.getScheme() + "://" + "localhost" + ":" + req.getServerPort() + "/store" + format + fileName;
//          transferTo(File dest) 将接收到的文件传输到给定的目标文件。
            multipartFile.transferTo(new File(realPath, fileName));

            String fileReal = fileDir + "//" + fileName;
//            System.out.println(fileReal);
            SubmitHomework submitHomework = submitHomeworkService.findSubmitHomeworkById(submitHomeworkId);
            submitHomework.setSubmitHomeworkFileRealPath(fileReal);
            submitHomework.setSubmitHomeworkFilePath(url);
            submitHomework.setSubmitHomeworkFileName(multipartFile.getOriginalFilename());
            submitHomeworkService.modifySubmitHomework(submitHomework);

            return R.ok().data("path", url);
        } else {
            return R.ok().message("请选中文件");
        }
    }

    @GetMapping("/downloadSubmitHomeworkFile/{submitHomeworkId}")
    public void downloadSubmitHomeworkFile(@PathVariable("submitHomeworkId") long submitHomeworkId,
                         HttpServletResponse response) {
        SubmitHomework submitHomework = submitHomeworkService.findSubmitHomeworkById(submitHomeworkId);
        String fileRealPath = submitHomework.getSubmitHomeworkFileRealPath();
        String fileName = submitHomework.getSubmitHomeworkFileName();
        File file = new File(fileRealPath);
        byte[] buffer = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            //文件是否存在
            if (file.exists()) {
                response.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有
                //设置响应
                response.setContentType("application/octet-stream;charset=UTF-8");
                // 将响应头中的Content-Disposition暴露出来,不然前端获取不到
                response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
                // 在响应头中的Content-Disposition里设置文件名称
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//                response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
                os = response.getOutputStream();
                bis = new BufferedInputStream(new FileInputStream(file));
                while (bis.read(buffer) != -1) {
                    os.write(buffer);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (os != null) {
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

CorsConfig.java

package com.wang.youketang.common.config;


import com.wang.youketang.common.interceptor.JWTInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer{
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 允许跨域访问的路径  '/**'表示应用的所有方法
        registry.addMapping("/**")

                .allowedOrigins("*")
//                .allowedOrigins("http://172.17.160.1:8080") //ip地址+端口号
//                .allowedOrigins("http://172.18.29.108:8080") //前端vue的ip
//                .allowedOrigins("http://172.17.160.1:8080")  //本机的ip
                // 允许跨域访问的来源 '*'表示所有域名来源

                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                // 是否允许发送cookie true-允许 false-不允许 默认false。对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json,这个值只能设为true
                .allowCredentials(true)
                // 预检间隔时间1小时,单位为秒。指定本次预检请求的有效期,在有效期间,不用发出另一条预检请求。
                // 浏览器发出CORS简单请求,只需要在头信息之中增加一个Origin字段
                // 浏览器发出CORS非简单请求,会在正式通信之前,增加一次OPTIONS查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
                .maxAge(3600)
                // 允许跨域请求可携带的header,'*'表所有header头。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定
                .allowedHeaders("*");
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //   访问相对路径
        // PS:注意文件路径最后的斜杠(文件分隔符),如果缺少了,就不能够正确的映射到相应的目录
        String baseDocumentPath = "file:D:/document/";
        String baseStorePath = "file:D:/store/";
//        String baseDocumentPath = "file:/www/wwwroot/resource/document/";
//        String baseStorePath = "file:/www/wwwroot/resource/store/";
        //        /www/wwwroot/resource
        registry.addResourceHandler("/document/**").addResourceLocations(baseDocumentPath);
        registry.addResourceHandler("/store/**").addResourceLocations(baseStorePath);
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }

    //注册拦截器
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**")    //需要token验证的接口 一般是全部接口
                .excludePathPatterns("/student/**","/teacher/**","/document/**","/store/**");  //
    }

}