若依-了解头像(文件)上传流程

2023-11-07

周知

本文主要记录本人关于自主学习若依框架的部分心得经验,必定有许多不足甚至理解有误的部分,如果对你有帮助我也不胜欢喜;如果发现有错误的地方也希望能够分享指出,一起加油

需求原因

客户内部系统,一般不对外开放,因此不适合将文件(如图片)存放到云上,所以存放在本地服务器中

流程分析

每个(组)截图会配上本人的理解和分析,有不对或不全的地方万望指出

页面

在这里插入图片描述

登录后任意界面点击右上角头像位置选择进入个人中心,选择点击头像位置弹出该窗口,选择本地图片上传;
前端调用接口完成头像更新,在数据库的体现为头像字段内容由空转为图片保存地址
在这里插入图片描述
存取地址默认会将profile替换为若依后端配置的默认文件夹地址
/profile ——> D:/ruoyi/uploadPath

前端

ruoyi-ui\src\views\system\user\profile\userAvatar.vue
在这里插入图片描述
ruoyi-ui\src\api\system\user.js
在这里插入图片描述

若依前端不进行什么处理,负责将页面接收到的文件调用后端接口传到后端,并将图片的读取地址改为后端传回来的保存地址

后端

设计到的类中代码可能过多不便全部截出,附上相对路径可自行查看
src\main\java\com\ruoyi\web\controller\system\SysProfileController.java
在这里插入图片描述

后端获取到前端传来的文件,进行通用的校验和处理
判空、拼接存储地址、更新用户信息(头像地址)、更新token、返回头像地址

src\main\java\com\ruoyi\common\utils\file\FileUploadUtils.java
在这里插入图片描述

若依的文件工具类对传来的文件进行校验和处理
判断文件名是否过长、扩展名(文件类型)是否规范合法、拼接存储地址、调用jar包类和方法进行文件的保存
———————
后面还有两个重载的方法,实际上并不进行什么处理,只是为了应对其他使用场景(如不传)存储文件夹、扩展名等……最终都是调用上述方法进行存储操作

在这里插入图片描述在这里插入图片描述

涉及到的jar包、内置类

jetbrains://idea/navigate/reference?project=ifs_7_0_java&path=E:/Maven/develop/apache-maven-3.5.3/repository/org/springframework/spring-web/5.3.20/spring-web-5.3.20.jar!/org/springframework/web/multipart/MultipartFile.class
在这里插入图片描述

这是是关于以上截图代码中调用到的getOriginalFilename()和transferTo() 方法;
transferTo() 调用到FileCopyUtils工具类进行文件读写以实现头像的本地保存

jetbrains://idea/navigate/reference?project=ifs_7_0_java&path=E:/Maven/develop/apache-maven-3.5.3/repository/org/springframework/spring-core/5.3.20/spring-core-5.3.20.jar!/org/springframework/util/FileCopyUtils.class
在这里插入图片描述

若依文件工具类调用该类的方法进行文件的读写

java\io\OutputStream.java
在这里插入图片描述

该方法为上一张图中的 out.weite(in); 所调用,进行文件写入

jetbrains://idea/navigate/reference?project=ifs_7_0_java&path=E:/Maven/develop/apache-maven-3.5.3/repository/org/springframework/spring-core/5.3.20/spring-core-5.3.20.jar!/org/springframework/util/StreamUtils.class
在这里插入图片描述

同样是对于文件的输入输出流操作;
nutNull() 方法:如果入参1为空,返回message为入参2的异常

附上若依默认文件地址的配置

src\main\resources\application.yml
在这里插入图片描述

新增需求

强化文件类型校验

思路

除了后缀校验之外,另外增加文件真实类型校验

资料

https://blog.csdn.net/qq_42764468/article/details/121522645

实现

src\main\java\com\ruoyi\common\utils\file\FileTypeEnum.java

package com.ruoyi.common.utils.file;

import lombok.Getter;
import java.util.ArrayList;
import java.util.List;

@Getter
public enum FileTypeEnum {
    /**
     * 允许上传的附件类型集合
     */
    // 主要是图片,其他的先注释掉了
    JPEG("jpeg", "FFD8FF"),
    JPG("jpg", "FFD8FF"),
    PNG("png", "89504E47"),
    BMP("bmp", "424D");
//    RTF("rtf", "7B5C727466"),
//    DOC("doc", "D0CF11E0"),
//    DOCX("docx", "504B030414"),
//    PDF("pdf", "255044462D312E");

    /**
     * 允许上传的文件类型的文件后缀
     */
    private final String suffixName;

    /**
     * 允许上传的文件类型的文件头信息
     */
    private final String headCode;

    /**
     * 构造方法
     *
     * @param suffixName 文件后缀名
     * @param headCode   文件头信息
     */
    FileTypeEnum(String suffixName, String headCode) {
        this.suffixName = suffixName;
        this.headCode = headCode;
    }

    /**
     * 获取允许上传的文件类型集合
     *
     * @return List-String
     */
    public static List<String> getFileType() {
        List<String> fileTypeList = new ArrayList<>();
        for (FileTypeEnum fileTypeEnum : FileTypeEnum.values()) {
            fileTypeList.add(fileTypeEnum.getSuffixName());
        }
        return fileTypeList;
    }
}


src\main\java\com\ruoyi\common\utils\file\FileHeaderUtils.java

package com.ruoyi.common.utils.file;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Slf4j
public class FileHeaderUtils {
    /**
     * 文件类型和文件大小校验
     *
     * @param file            上传的附件
     * @param allowedFileType 限制上传附件的类型
     */
    public static String checkFileHeader(MultipartFile file, Set<String> allowedFileType) throws InvalidExtensionException {
        // 去掉了后缀校验和大小校验
        String fileType;
        String fileName = file.getOriginalFilename();
        // 为了防止报错增加的两个变量
        String fileHeader = "其他类型";
        String[] alloweds = new String[allowedFileType.size()];
        // 给alloweds赋值
        int i = 0;
        for (String s : allowedFileType) {
            alloweds[i] = s;
            i++;
        }
        // 文件类型判断 - 校验文件头内容
        try (InputStream inputStream = file.getInputStream()) {
            // 获取到上传文件的文件头信息
            fileHeader = FileHeaderUtils.getFileHeader(inputStream);

            if (StringUtils.isBlank(fileHeader)) {
                log.error("Failed to get file header content.");
                throw new InvalidExtensionException(alloweds, fileHeader, fileName);
//                throw new CommonException(BizCodeEnum.FILE_UPLOAD_TYPE_NOT_ALLOWED);
            }
            // 根据上传文件的文件头获取文件的真实类型
            fileType = getFileType(fileHeader);
            if (StringUtils.isBlank(fileType) || !fileTypeAllowed(fileType, allowedFileType)) {
                log.error("Unsupported file type: [{}]", fileType);
                throw new InvalidExtensionException(alloweds, fileType, fileName);
//                throw new CommonException(BizCodeEnum.FILE_UPLOAD_TYPE_NOT_ALLOWED);
            }
        } catch (IOException | InvalidExtensionException e) {
            log.error("Get file input stream failed.", e);
            throw new InvalidExtensionException(alloweds, fileHeader, fileName);
//            throw new CommonException(BizCodeEnum.ATTACHMENT_UPLOAD_ERROR);
        }
        return fileType;
    }

    /**
     * 文件类型校验
     *
     * @param fileType    待校验的类型
     * @param allowedType 允许上传的文件类型
     * @return true - 满足,false - 不满足
     */
    private static boolean fileTypeAllowed(String fileType, Set<String> allowedType) {
        if (StringUtils.isBlank(fileType) || CollectionUtils.isEmpty(allowedType)) {
            return false;
        }
        return allowedType.contains(fileType);
    }

    /**
     * 据文件的头信息获取文件类型
     *
     * @param fileHeader 文件头信息
     * @return 文件类型
     */
    public static String getFileType(String fileHeader) {
        if (fileHeader == null || fileHeader.length() == 0) {
            return null;
        }
        fileHeader = fileHeader.toUpperCase();
        FileTypeEnum[] fileTypes = FileTypeEnum.values();
        for (FileTypeEnum type : fileTypes) {
            boolean b = fileHeader.startsWith(type.getHeadCode());
            if (b) {
                return type.getSuffixName();
            }
        }
        return null;
    }

    /**
     * 文件头字节数组转为十六进制编码
     *
     * @param content 文件头字节数据
     * @return 十六进制编码
     */
    private static String bytesToHexString(byte[] content) {
        StringBuilder builder = new StringBuilder();
        if (content == null || content.length <= 0) {
            return null;
        }
        String temp;
        for (byte b : content) {
            temp = Integer.toHexString(b & 0xFF).toUpperCase();
            if (temp.length() < 2) {
                builder.append(0);
            }
            builder.append(temp);
        }
        return builder.toString();
    }

    /**
     * 获取文件的文件头信息
     *
     * @param inputStream 输入流
     * @return 文件头信息
     * @throws IOException 异常
     */
    private static String getFileHeader(InputStream inputStream) throws IOException {
        byte[] content = new byte[28];
        inputStream.read(content, 0, content.length);
        return bytesToHexString(content);
    }
}


src\main\java\com\ruoyi\common\utils\file\FileUploadUtils.java

/**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException
    {
        // 文件大小
        long size = file.getSize();
        // 不能超过最大值,默认50M
        if (size > DEFAULT_MAX_SIZE)
        {
            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
        }
        // 获取文件名、--扩展名--
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        // 扩展名非空但不被允许——>判断非法类型
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
        {
            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
                        fileName);
            }
            else
            {
                throw new InvalidExtensionException(allowedExtension, extension, fileName);
            }
        }
        // 获取到允许文件头
        List<String> fileType = FileTypeEnum.getFileType();
        Set<String> typeSet = new HashSet<>();
        for (String s : fileType) {
            // 添加到Set中
            typeSet.add(s);
        }
        // 校验文件头
        FileHeaderUtils.checkFileHeader(file, typeSet);
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

若依-了解头像(文件)上传流程 的相关文章

随机推荐

  • 【可解释性机器学习】interpretable machine learning——Functional Decomposition

    Functional Decomposition 机器学习中的监督学习模型可被视为一个函数 该函数将高维特征向量作为输入 然后产生预测或分类概率作为输出 函数分解 functional decomposition 分解高维函数并将其表达为可
  • 常见前端安全问题概述

    随着互联网的高速发展 安全问题已成为企业最关注的焦点之一 而前端又是容易引发安全问题的 窗口 作为开发人员的我们 更需要充分了解如何预防和修复安全漏洞 本文将列举常见的前端安全问题 希望对你有所帮助 本文将从以下几种安全问题展开介绍 XSS
  • Jmeter中csvRead函数的使用

    当想要脚本随机传参数时 可以结合csvRead和Random函数使用 也相当于参数化的一种用法 想了解其他参数化方法的读者 可以参考上一篇文档 1 事先准备好存储数据的文档 注意 数据之间使用英文逗号隔开 否则后面随机抽取数据时没有抽取到
  • 【yarn】yarn Job 状态机正常执行流程

    1 概述 今天6月1日 节日值得发个文章 庆祝一下 上一篇文章 Yarn Yarn Service端如何处理客户端提交的任务 在上一篇文章中 我们知道服务器接收到客户端提交的任务之后 会启动多个状态机进行联合操作 最终来解决任务提交之后的全
  • JS内置对象Math的常用方法

    JS内置对象Math的常用方法 1 向上取整 Math ceil 2 向下取整 Math floor 3 四舍五入 Math round 4 绝对值 Math abs 最大值 Math max 最小值 Math min 7 随机数 Math
  • 5 种方法重复执行历史命令

    Linux 下 如果要执行一条或多条之前输过的指令 要怎么处理 很多人会想到使用上下箭头去翻查历史输入的命令 这当然是可以了 除了这种方法 本文再介绍另外 5 种方法来实现这样的效果 在正式开始之前 我们先随便执行几条命令 便于后面演示 为
  • Anaconda 更换镜像源、创建虚拟环境并安装 PyTorch

    文章目录 1 更换镜像源 2 选择合适的 CUDA Runtime 版本 2 1 CUDA Runtime 版本不能高于 CUDA Driver 版本 2 2 根据显卡的算力和架构确定 CUDA Runtime 版本 2 3 找到安装 Py
  • Ps2021软件安装Mac(含M1)、Windows版

    一 下载链接 Mac版本 1 M1芯片适用 百度网盘下载地址 提取码 rpyn 2 M1不适用 系统10 15及以上 下载地址 Windows版本 Ps2022 64位 此版本不支持LTSC版本系统 百度网盘下载地址 提取码 wb2d 二
  • MySQL: 运算符使用练习

    前言 练习运算符的使用 加强记忆 案例目的 在已建数据库中创建数据表 并对表中数据进行处理 练习运算符 包括数据运算符 逻辑运算符 位运算符 的使用 操作过程 创建名为 tb15 的数据表 包含 VARCHAR 100 类型的字段 note
  • 在vue中使用this.$refs报错undefined找不到子组件的方法

    最近遇见个问题 在父组件调用子组件的方法时报错undefined 这种情况一般都是父组件调用子组件方法的时候 dom还没更新成功 可以使用 this nextTick 这个方法作用是当数据被修改后使用这个方法会回调获取更新后的dom再渲染出
  • Spring MVC视图解析器

    Spring MVC视图解析器 AbstractCachingViewResolver XmlViewResolver ResourceBundleViewResolver UrlBasedViewResolver InternalReso
  • 报错Caused by java lang ClassNotFoundException Didn't find c

    分享一下我老师大神的人工智能教程 零基础 通俗易懂 风趣幽默 还带黄段子 希望你也加入到我们人工智能的队伍中来 https blog csdn net jiangjunshow 报错信息 03 14 20 24 09 675 15801 1
  • 赛码-接金币-java

    题目描述 小赛非常喜欢玩游戏 最近喜欢上了一个接金币的游戏 在游戏中 使用帽子左右移动接金币 金币接的越多越好 但是金币掉到地上就不能再接了 为了方便问题的描述 我们把电脑屏幕分成11格 帽子每次能左右移动一格 现在给电脑屏幕如图标上坐标
  • 浅谈systemd

    浅谈systemd systemd的基本概念 Systemd的管理服务 Systemd的管理运行级别 systemd的基本概念 一 system的简要介绍 定义 系统启动和服务器守护进程管理器 负责在系统启动或运行时 激活系统资源 服务器进
  • 使用Docker安装Portainer

    打开powershell输入命令 docker run d p 9000 9000 restart always v var run docker sock var run docker sock name prtainer portain
  • 双轮平衡车实现自平衡功能

    1 功能说明 在双轮小车上安装一个六轴陀螺仪传感器 本文示例将实现双轮小车自主平衡功能 2 电子硬件 在这个示例中 我们采用了以下硬件 请大家参考 主控板 Basra主控板 兼容Arduino Uno 扩展板 Bigfish2 1扩展板 传
  • 【Java】Java中的“引用类型”和C中的“指针”区别

    文章目录 前言 1 Java中 基本数据类型 和 引用数据类型 变量在内存分配时的不同 2 C中 指针 的特点 3 Java中 引用 的特点 4 Java的参数传递 5 参考 前言 在学习Java中变量的数据类型时 发现其分为2大类 基本数
  • spring加载流程之ConfigurationClassPostProcessor

    spring加载流程之ConfigurationClassPostProcessor ConfigurationClassPostProcessor postProcessBeanDefinitionRegistry processConf
  • FPGA面试真题解析

    FPGA面试真题解析 1 1 十进制46 25对应的二进制表达式为 硬件逻辑实习岗 A 101110 11 B 101101 01 C 101110 1 D 101110 01 解析 这个问题看上去很简单 那是因为我们平时可以打开电脑上的计
  • 若依-了解头像(文件)上传流程

    周知 本文主要记录本人关于自主学习若依框架的部分心得经验 必定有许多不足甚至理解有误的部分 如果对你有帮助我也不胜欢喜 如果发现有错误的地方也希望能够分享指出 一起加油 需求原因 客户内部系统 一般不对外开放 因此不适合将文件 如图片 存放