SpringBoot: 浅谈文件上传和访问的坑 (MultiPartFile)

本次的项目环境为 SpringBoot 2.0.4, JDK8.0. 服务器环境为CentOS7.0, Nginx的忘了版本.


前言


SpringBoot使用MultiPartFile接收来自表单的file文件,然后进行服务器的上传是一个项目最基本的需求,我以前的项目都是基于SpringMVC框架搭建的,所以在使用SpringBoot的时候进行MultiPartFile上传遇到了坑,这里说一下,其中主要包含两个坑点.

  • 使用transferTo()方法写入File时找不到文件路径.

  • 访问文件时Nginx的403 forbidden问题.


使用transferTo()方法写入File时找不到文件路径


在我们解决问题之前,我们先看一下封装的上传方法以及报错日志.

    public static final String BASE_PATH = "/test/";

    public static String upload(MultipartFile imageFile) {

        if (imageFile.isEmpty()) {
            return null;
        }
        String filename = imageFile.getOriginalFilename();
        
        String ext= null;
        if(filename.contains(".")){
            ext = filename.substring(filename.lastIndexOf("."));
        }else{
            ext = "";
        }
        
        String uuid =  UUID.randomUUID().toString().replaceAll("-", "");
        String nfileName = uuid + ext;
        String dirPath = DateFormatUtils.format(new Date(), "yyyyMMdd");
        String filepath = BASE_PATH.endsWith("/") ? BASE_PATH+dirPath : BASE_PATH+"/"+dirPath;
        File targetFile = new File(filepath, nfileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        } else {
            targetFile.delete();
        }
        try {
            imageFile.transferTo(targetFile);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        String accessUrl =  "/"+nfileName;
        logger.debug("上传文件成功 URL:" + nfileName);
        return accessUrl;
    }

报错日志如下所示.

java.io.IOException: java.io.FileNotFoundException: /test/20181025/be3676dffca94c6dac5e96a1a41dcd97.jpg (Is a directory)
    at org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:122)
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.transferTo(StandardMultipartHttpServletRequest.java:255)
    at com.dong.runline.common.utils.UploadUtils.upload(UploadUtils.java:56)
    at com.dong.runline.controller.TimeLineController.createTimeLineAction(TimeLineController.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

这里就出现了java.io.FileNotFoundException错误,这是怎么造成的呢?,通过Debug下的断点我们发现是下面的位置发生了错误.

这里我用的本地环境进行了测试,发现本地创建了这个样的一个路径,最后的图片被创建成一个这样的路径.

在SpringMVC环境下并没有这样的问题,在SpringBoot却出现了这样的问题,那么到底怎么造成的呢?网上的很多博客写到,通过查询transferTo()方法源码找到了问题关键所在.

@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
    this.part.write(dest.getPath());
}

我们接着进入write()方法.

    @Override
    public void write(String fileName) throws IOException {
        File file = new File(fileName);
        if (!file.isAbsolute()) {
            file = new File(location, fileName);
        }
        try {
            fileItem.write(file);
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

这时候我们看到如果!file.isAbsolute()成立,也就是我们没有使用绝对路径,那么file = new File(location,fileName);会在原来的基础上加上location路径.这就是原因所在,解决起来也很方便,网上总共有两种方案.

  • 使用绝对路径
  • 修改location的值

第一种方案我们就不过多解释了,我们看一下如何修改location的值.我们只需要在启动类中注入如下Bean即可.把路径指向我们的存储路径.

    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setLocation(UploadUtils.BASE_PATH);
        return factory.createMultipartConfig();
    }

然后我们再修改下UploadUtils中的创建File方法即可.

        String uuid =  UUID.randomUUID().toString().replaceAll("-", "");
        String nfileName = uuid + ext;
        File targetFile = new File(nfileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        } else {
            targetFile.delete();
        }


访问文件时Nginx的403 forbidden问题


所谓的Nginx的403错误其实就是访问权限错误.当前用户没有访问该资源的权限,这样理解的话,我们就有两种方案可行.一,降低文件访问的权限等级.二,升高用户的访问权限.下面我们一个一个来看一下如何进行实现.

  • 降低文件访问的权限等级

降低文件的访问权限,我们只需要用到 chmod指令即可.这里简单解释一下chmod指令.

在Mac的使用过程中我们也经常会修改 某个文件的权限,例如:

chmod 777 file

如果如上设置的话,那么任何一个用户都会对这个file文件拥有全部权限.

那么为什么是三位数呢?这是因为这三位数分别代表着档案拥有者User、群组Group、其他Other三者的权限.也就是说拥有者的权限等级为7,群组的权限等级为7,其他权限等级也为7.

那么为什么是7呢?这是因为一个linux文件总共有三种权限,分别是读r,写w,操作x.对应的值分别是4,2,1.当一个用户对某个文件拥有7的数值时,这时候为4+2+1,也就是说他拥有该文件全部的权限.

上面说了 chmod指令的如何使用,那么接下来我们就可以对服务器的文件使用chmod 664 file指令,然后降低文件访问的权限等级.使全部用户都拥有文件的访问权限.但是问题来了,难道用户上传一次,我们就需要手动修改一次文件的权限,这显然是不正确的,那么我们该怎么办呢?这时候我们就需要提高用户的访问权限了.

  • 升高用户的访问权限

提高用户的访问权限,这里其实是修改Nginx的启动者,我们把启动者设置为最多权限者,那么我们就可以访问到文件了.

首先我们先看是谁启动了Nginx需要用到如下的指令.

 ps aux | grep "nginx: worker process" | awk '{print $1}'

这里我已经做了修改,截图如下所示.

本来要是不对Nginx的配置进行任何设置访问的话,那么第一个root应该为nobody,也就是Nginx的启动者.先前已经使用** ls -l file **指令查询了文件的权限情况,root 拥有读写权限,other没有任何权限.所以我们要把启动者改为root即可.

打开Nginx配置文件所在的位置,{nginx}表示你的nginx安装路径.

vi {nginx}/conf/nginx.conf

添加启动者,如下所示.

user root

返回到sbin目录中,准备检测配置文件和重新启动Ngnix.

cd ../sbin/

检测配置文件的正确性

./nginx -t

检测没有任何问题,重新启动

./nginx -s reload

这时候即可正常访问到文件了.


结语


这篇博客算是日常的问题收集吧,整理一下.没什么可多说的,就是搞事.欢迎关注骚栋



©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,825评论 6 546
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,814评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,980评论 0 384
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 64,064评论 1 319
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,779评论 6 414
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,109评论 1 330
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,099评论 3 450
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,287评论 0 291
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,799评论 1 338
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,515评论 3 361
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,750评论 1 375
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,221评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,933评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,327评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,667评论 1 296
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,492评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,703评论 2 380

推荐阅读更多精彩内容