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 <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> upload(MultipartFile imageFile) {
<span class="hljs-keyword">if</span> (imageFile.isEmpty()) {
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
<span class="hljs-built_in">String</span> filename = imageFile.getOriginalFilename();
<span class="hljs-built_in">String</span> ext= <span class="hljs-literal">null</span>;
<span class="hljs-keyword">if</span>(filename.contains(<span class="hljs-string">"."</span>)){
ext = filename.substring(filename.lastIndexOf(<span class="hljs-string">"."</span>));
}<span class="hljs-keyword">else</span>{
ext = <span class="hljs-string">""</span>;
}
<span class="hljs-built_in">String</span> uuid = UUID.randomUUID().toString().replaceAll(<span class="hljs-string">"-"</span>, <span class="hljs-string">""</span>);
<span class="hljs-built_in">String</span> nfileName = uuid + ext;
<span class="hljs-built_in">String</span> dirPath = DateFormatUtils.format(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(), <span class="hljs-string">"yyyyMMdd"</span>);
<span class="hljs-built_in">String</span> filepath = BASE_PATH.endsWith(<span class="hljs-string">"/"</span>) ? BASE_PATH+dirPath : BASE_PATH+<span class="hljs-string">"/"</span>+dirPath;
File targetFile = <span class="hljs-keyword">new</span> File(filepath, nfileName);
<span class="hljs-keyword">if</span> (!targetFile.exists()) {
targetFile.mkdirs();
} <span class="hljs-keyword">else</span> {
targetFile.delete();
}
<span class="hljs-keyword">try</span> {
imageFile.transferTo(targetFile);
} <span class="hljs-keyword">catch</span> (IllegalStateException e) {
e.printStackTrace();
} <span class="hljs-keyword">catch</span> (IOException e) {
e.printStackTrace();
}
<span class="hljs-built_in">String</span> accessUrl = <span class="hljs-string">"/"</span>+nfileName;
logger.debug(<span class="hljs-string">"上传文件成功 URL:"</span> + nfileName);
<span class="hljs-keyword">return</span> 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
这时候即可正常访问到文件了.
结语
这篇博客算是日常的问题收集吧,整理一下.没什么可多说的,就是搞事.欢迎关注骚栋
</div>
SpringBoot: 浅谈文件上传和访问的坑 (MultiPartFile)的更多相关文章
- SpringBoot项目实现文件上传和邮件发送
前言 本篇文章主要介绍的是SpringBoot项目实现文件上传和邮件发送的功能. SpringBoot 文件上传 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码. 开发准备 环境要 ...
- ie下文件上传无权访问的问题
最近项目遇到个问题,ie下文件上传无权访问,在网上找了很久才找到答案,原来是因为ie下不能用js触发input=file的点击事件,必须手动点击才可以.
- Springboot如何启用文件上传功能
网上的文章在写 "springboot文件上传" 时,都让你加上模版引擎,我只想说,我用不上,加模版引擎,你是觉得我脑子坏了,还是觉得我拿不动刀了. springboot如何启用文 ...
- SpringBoot(3) 文件上传和访问
springboot文件上传 MultipartFile file,源自SpringMVC MultipartFile 对象的transferTo方法,用于文件保存(效率和操作比原先用FileOutS ...
- 浅谈webuploader上传文件
官网:http://c7.gg/fw4sn 案例: 文件上传进度 // 文件上传过程中创建进度条实时显示. uploader.on( 'uploadProgress', function( file, ...
- SpringBoot: 6.文件上传(转)
1.编写页面uploadFile.html <!DOCTYPE html> <html lang="en"> <head> <meta c ...
- 浅谈异步上传插件 jquery-file-upload插件
当我们需要异步上传文件的时候,我们倾向于在网上查找相关的JQuery插件,jquery-file-upload就是我们经常看到的,但是他的主页是英文的,对于我们这些英语比较差的同学来说,简直就是... ...
- SpringBoot+BootStrap多文件上传到本地
1.application.yml文件配置 # 文件大小 MB必须大写 # maxFileSize 是单个文件大小 # maxRequestSize是设置总上传的数据大小 spring: servle ...
- 170706、springboot编程之文件上传
使用thymleaf模板,自行导入依赖! 一.单文件上传 1.编写单文件上传页面singleFile.html <!DOCTYPE html> <html xmlns="h ...
随机推荐
- Nginx教程(三) Nginx日志管理 (转)
Nginx教程(三) Nginx日志管理 1 日志管理 1.1 Nginx日志描述 通过访问日志,你可以得到用户地域来源.跳转来源.使用终端.某个URL访问量等相关信息:通过错误日志,你可以得到系统某 ...
- 重磅!容器集群监控利器 阿里云Prometheus 正式免费公测
Prometheus 作为容器生态下集群监控的首选方案,是一套开源的系统监控报警框架.它启发于 Google 的 borgmon 监控系统,并于 2015 年正式发布.2016 年,Prometheu ...
- RDS 5.7三节点企业版时代的数据一致性解决方案
上篇我们看到了在MySQL主备模式下,我们在数据一致性上做了不少事情,但解决方案都有一定的局限性,适合部分场景或者解决不彻底的问题.随着以Google Spanner以及Amazon Aruora 为 ...
- 介绍配置管理工具SVN的使用
配置管理CM(Configuration Mangerment) 一.配置管理工具SVN的介绍 ---Subversion ---是一个开放源代码的版本控制系统 ---时下流行的SVN和GIT 每天开 ...
- 2019-10-18-dotnet-文件读写务必注意事项
title author date CreateTime categories dotnet 文件读写务必注意事项 lindexi 2019-10-18 08:42:53 +0800 2019-10- ...
- poj 1845 【数论:逆元,二分(乘法),拓展欧几里得,费马小定理】
POJ 1845 题意不说了,网上一大堆.此题做了一天,必须要整理一下了. 刚开始用费马小定理做,WA.(poj敢说我代码WA???)(以下代码其实都不严谨,按照数据要求A是可以等于0的,那么结果自然 ...
- SharpDX初学者教程第2部分:创建窗口
原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-2-creating-a-window 在第二篇教程中,我们将介绍如何创建一个稍后将呈现的简 ...
- 项目中容易出现的BUG预警
之前没有记录BUG的习惯导致在同一个坑里边栽了好几次,于是将最近几个项目中遇到的问题整理一下,在进行新项目时预警一遍: 使用携带有搜索功能的分页查询时,注意当用户更改了查询条件但没有点击查询按钮直接点 ...
- Python错误:AttributeError: 'generator' object has no attribute 'next'解决办法
今天在学习生成器对象(generation object)运行以下代码时,遇到了一个错误: #定义生成器函数def liebiao(): for x in range(10): yield x#函数调 ...
- Protobuf c的使用范例
protobuffer (简称PB) 网上的文章一大堆,随便看看,PB使用起来非常方便.这里主要讲讲Protobuf C(简称PC)的使用 1,代码 https://github.com/protob ...