山东大学软件学院项目实训-基于大模型的模拟面试系统-Vditor编辑器上传图片

Vditor编辑器图片上传功能

使用Vditor进行图片上传时,会返回图片在后端的相对路径,这在前端是无法进行显示的(如下图)

于是为了将图片正常·显示,我采取了和头像上传一样的解决方案,使用阿里云图床进行存储。

实现步骤

首先定位Vditor编辑器向后端发送的请求,根据浏览器的开发者工具,我们找到了具体的API(如下图)

下面是UploadController.java文件中的与该次请求相关的方法。

java 复制代码
    @PostMapping("/file/batch")
    @Transactional(rollbackFor = Exception.class)
    public GlobalResult<JSONObject> batchFileUpload(@RequestParam(value = "file[]", required = false) MultipartFile[] multipartFiles, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) {
        TokenUser tokenUser = getTokenUser(request);
        File file = genFile(type);
        String typePath = FilePath.getPath(type);
        String localPath = Utils.getProperty("resource.file-path") + "/" + typePath + "/";
        Map<String, String> successMap = new HashMap<>(16);
        Set<String> errFiles = new HashSet<>();

        for (MultipartFile multipartFile : multipartFiles) {
            String orgName = multipartFile.getOriginalFilename();

            if (multipartFile.getSize() == 0) {
                errFiles.add(orgName);
                continue;
            }
            String fileType = FileUtils.getExtend(orgName);
            try {
                String md5 = DigestUtils.md5DigestAsHex(multipartFile.getBytes());
                String fileUrl = forestFileService.getFileUrlByMd5(md5, tokenUser.getIdUser(), fileType);
                if (StringUtils.isNotEmpty(fileUrl)) {
                    successMap.put(orgName, fileUrl);
                    continue;
                }
                String fileName = System.currentTimeMillis() + fileType;
                String savePath = file.getPath() + File.separator + fileName;
                File saveFile = new File(savePath);
                fileUrl = localPath + fileName;
                FileCopyUtils.copy(multipartFile.getBytes(), saveFile);
                forestFileService.insertForestFile(fileUrl, savePath, md5, tokenUser.getIdUser(), multipartFile.getSize(), fileType);
                successMap.put(orgName, localPath + fileName);
            } catch (IOException e) {
                errFiles.add(orgName);
            }

        }
        JSONObject data = new JSONObject(2);
        data.put("errFiles", errFiles);
        data.put("succMap", successMap);
        return GlobalResultGenerator.genSuccessResult(data);
    }

这段代码实现了一个批量文件上传的功能:

  • 主要逻辑部分:
    • 检查文件大小,跳过空文件
    • 计算文件MD5值用于去重
    • 检查数据库中是否已存在相同MD5的文件,如果存在则直接返回已有URL
    • 生成唯一文件名(时间戳+文件扩展名)
    • 构建文件保存路径
    • 将文件内容复制到目标位置
    • 在数据库中记录文件信息
    • 将文件URL添加到成功列表
  • 使用MD5进行文件去重,避免重复存储相同内容的文件
  • 使用事务确保数据一致性
  • 分别记录成功和失败的文件,提供完整的上传结果

要修改的就是file_url相关的部分,根据数据库表结构可以知道有两个列与路径有关,分别是file_pathfile_url,原本这两个列存储的是相同的值,现在进行修改将file_url改为存储真正的阿里云图床的URL。

首先在OSSUpload.java里添加一个新的上传方法:

java 复制代码
    /**
     * 上传MultipartFile文件到OSS
     * 
     * @param file MultipartFile文件
     * @param folder 文件夹路径
     * @return 访问URL
     * @throws IOException IO异常
     */
    public String uploadFileToOSS(MultipartFile file, String folder) throws IOException {
        try {
            // 1. 获取文件名和扩展名
            String originalFilename = file.getOriginalFilename();
            String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
            
            // 2. 生成唯一文件名
            String fileName = folder + UUID.randomUUID() + fileType;
            
            // 3. 上传文件到OSS
            ossClient.putObject(
                    ossConfig.getBucketName(),
                    fileName,
                    new ByteArrayInputStream(file.getBytes())
            );
            
            // 4. 返回访问URL
            return "https://" + ossConfig.getBucketName() + "." + ossConfig.getEndpoint() + "/" + fileName;
        } catch (Exception e) {
            throw new RuntimeException("上传文件到OSS失败: " + e.getMessage(), e);
        }
    }

然后修改batchFileUpload方法的逻辑:

java 复制代码
    @PostMapping("/file/batch")
    @Transactional(rollbackFor = Exception.class)
    public GlobalResult<JSONObject> batchFileUpload(@RequestParam(value = "file[]", required = false) MultipartFile[] multipartFiles, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) {
        TokenUser tokenUser = getTokenUser(request);
        File file = genFile(type);
        String typePath = FilePath.getPath(type);
        String localPath = Utils.getProperty("resource.file-path") + "/" + typePath + "/";
        Map<String, String> successMap = new HashMap<>(16);
        Set<String> errFiles = new HashSet<>();

        for (MultipartFile multipartFile : multipartFiles) {
            String orgName = multipartFile.getOriginalFilename();

            if (multipartFile.getSize() == 0) {
                errFiles.add(orgName);
                continue;
            }
            String fileType = FileUtils.getExtend(orgName);
            try {
                String md5 = DigestUtils.md5DigestAsHex(multipartFile.getBytes());
                String fileUrl = forestFileService.getFileUrlByMd5(md5, tokenUser.getIdUser(), fileType);
                if (StringUtils.isNotEmpty(fileUrl)) {
                    successMap.put(orgName, fileUrl);
                    continue;
                }
                String fileName = System.currentTimeMillis() + fileType;
                String savePath = file.getPath() + File.separator + fileName;
                File saveFile = new File(savePath);
//                fileUrl = localPath + fileName;
                // 使用OSS上传文件
                fileUrl = ossUpload.uploadFileToOSS(multipartFile, typePath + "/article");
                successMap.put(orgName, fileUrl);
                FileCopyUtils.copy(multipartFile.getBytes(), saveFile);
                forestFileService.insertForestFile(fileUrl, savePath, md5, tokenUser.getIdUser(), multipartFile.getSize(), fileType);
//                successMap.put(orgName, localPath + fileName);
            } catch (IOException e) {
                errFiles.add(orgName);
            }

        }
        JSONObject data = new JSONObject(2);
        data.put("errFiles", errFiles);
        data.put("succMap", successMap);
        return GlobalResultGenerator.genSuccessResult(data);
    }

最后,图片能够正常上传和显示:

相关推荐
风止何安啊11 小时前
🚦 前端并发请求 “交通管制”:别让你的接口堵成早高峰
前端·javascript·面试
Fox爱分享11 小时前
字节二面:1000瓶酒,有一瓶是毒药,多少只老鼠可以查出来?
算法·面试·程序员
Fox爱分享12 小时前
字节二面智力题:100只老虎和1只羊关在一起,这只羊会不会被吃?
算法·面试·程序员
学iOS很快乐12 小时前
Pinterest Staff SDE 五轮面试全过,加拿大 TC 500K CAD,附 OA 真题和每轮考点
面试·职场和发展
黄敬峰14 小时前
从“聊天”到“做事”:构建你的第一个高性能 LangChain Agent
面试
KaifuZeng16 小时前
通信与接口协议面试十一、网口
嵌入式硬件·面试·通信与接口协议
Robot_Nav16 小时前
C++ 面试常问问题汇总:基础语法、面向对象、STL、多线程与设计模式
c++·设计模式·面试
wear工程师16 小时前
腾讯天美一面:从 HashMap 到 Spring 事务,面试官这套连环问到底在考什么
java·面试
触底反弹17 小时前
面试被问 RAG 只能说出六个字?这篇用 100 行 Node.js 代码帮你彻底搞懂
javascript·人工智能·面试
用户8524950718417 小时前
Agent 智能体到底是什么:一文讲透 ReAct 循环
面试