在制作java项目时,我们会疑惑,如果我们想要把本地的图片或者文档上传到服务器,我们该怎么做呢?为实现这个,应该这样做。
案例如下:
1、使用spring框架实现文件上传到服务器并在本地目录生成的功能,可用在上传图片功能和导入excel功能
2、具体实现流程是前端发送请求后端来处理,前端页面如下,这篇文章主要讲述后端业务处理,适合java有些基础的人学习
3、业务逻辑梳理
想要实现文件上传,必须要定义文件上传的路径,这个路径是服务器所在的路径,在服务器中开辟空间,把本地的文件上传,这是总的,下面一条一条代码分析
// 上传文件路径
String filePath = NiuaConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
//将路径进行拼接
fileName = filePath + File.separator + fileName;
//根据路径生成 FileInputStream输入流,前三部是生成上传并在本地生成文件,这一步是读取文件,例如想要读取excel进行操作
FileInputStream inputStream = new FileInputStream(new File(fileName));
首先获取上传路径,使用NiuaConfig.getUploadPath()方法,里面通过读取注解获取 yml 配置文件 ,返回
“profile+upload”
// String filePath = NiuaConfig.getUploadPath() 方法
public static String getUploadPath()
{
//返回路径,getProfile()通过注解读取yml文件
return getProfile() + "upload"; D:\niua\upload
}
public static String getProfile()
{
return profile;
}
创建读取我配置文件的实体类,通过@ConfigurationProperties(prefix = “配置文件名称”) 注解读取配置文件的属性,获取profile的值,定义profile的get和set方法来设置值和获取
// NiuaConfig 中的getProfile()
@Component
@ConfigurationProperties(prefix = "配置文件名称")
public class NiuaConfig {
/** 上传路径 */
private static String profile;
public static String getProfile()
{
return profile;
}
public void setProfile(String profile)
{
NiuaConfig.profile = profile;
}
/**
* 获取头像上传路径
*/
public static String getAvatarPath()
{
return getProfile() + "avatar";
}
/**
* 获取下载路径
*/
public static String getDownloadPath()
{
return getProfile() + "download/";
}
/**
* 获取上传路径
*/
public static String getUploadPath()
{
return getProfile() + "upload";
}
}
配置文件属性,在yml配置文件中,写入profile属性,通过注解来读取
FileUploadUtils.upload(filePath, file)方法将刚才获取的路径和file对象传入
// String fileName = FileUploadUtils.upload(filePath, file);
// baseDir 为绝对路径 , 文件对象file, 这MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION允许上传的格式
public static final String upload(String baseDir, MultipartFile file) throws IOException
{
try
{
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
以下代码是 return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION) 中的方法详解,
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{ //获取名字长度
int fileNamelength = file.getOriginalFilename().length();
//判断是数据大小
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
//校验文件类型,file为传来的file对象,allowed为传来的文件类型
assertAllowed(file, allowedExtension);
//根据一定规则生成文件名
String fileName = extractFilename(file);
//在服务器端生成file对象,在服务器中开辟二进制空间,没有在服务器上,应该先建出来
File desc = getAbsoluteFile(baseDir, fileName);
//上传的二进制数据写出本地新建的数据,这一步上传已经成功了
file.transferTo(desc);
//生成url,通过url就可以访问文件
// String pathFileName = getPathFileName(baseDir, fileName);
return fileName;
}
assertAllowed(file, allowedExtension) 是文件的校验,包括对文件的大小和类型
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, InvalidExtensionException
{ //文件大小的校验,文件大小不对抛出异常
long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
{
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
//获取 file的original名字,original:初始的
String fileName = file.getOriginalFilename();
//获取file对象的extension类型
String extension = getExtension(file);
//文件格式校验,判断allowedExtension是否为空,判断file的类型是否是允许的类型
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
{ //这些if 和 elseif 都是对类型的判断
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
{
throw new InvalidExtensionException(allowedExtension, extension, fileName);
}
}
}
String fileName = extractFilename(file)是生成名字,包含时间的名字和类型
public static final String extractFilename(MultipartFile file)
{
//获取后缀名
String extension = getExtension(file);
//拼接名字 DateUtils.datePath()获取当前时间 日期路径 即年/月/日 如2018/08/08
String fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
return fileName;
}
其中DateUtils.datePath()为获取当前是时间,并且格式为”yyyy/MM/dd”,这个主要是为了根据时间名字生成目录
,例如目录
/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static final String datePath()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
IdUtils.fastUUID()方法是获取随机UUID,UUID可以理解为文件名代码
例如文件名
/**
* 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
*
* @return 随机UUID
*/
public static String fastUUID()
{
return UUID.fastUUID().toString();
}
upload方法中的File desc = getAbsoluteFile(baseDir, fileName)方法,在前面的方法中,我们已经校验文件,生成文件名,现在就要把文件上传到服务器,而这个方法是在服务器中开辟存储空间,挖出一块空间。
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
{ //生成File类型数据 根据uploadDir绝对路径 ,和生成的fileName,在服务器弄出来空间
File desc = new File(uploadDir + File.separator + fileName);
//判断父级目录是否存在
if (!desc.getParentFile().exists())
{
//如果父级目录不存在,新建
desc.getParentFile().mkdirs();
}
if (!desc.exists())
{
//如果文件不存在,建立
desc.createNewFile();
}
return desc;
}
upload方法中的file.transferTo(desc)方法,前面的方法中,我们已经将空间开辟好了,就等将文件放入,这个方法就是将文件放入。file文件放入 开辟的desc中
void transferTo(File var1) throws IOException, IllegalStateException;
通过上面操作文件的上传已经完成了,可以在定义的 例如 D:\test\upload\2022\05\16 找到服务器生成的文件,路径是D:\test\ 时yml中配置的,upload 是 +“upload”进行拼接的,\2022\05\16是根据获取时间方法 得到的,成功的话会有下面类似的文件,上传少个文件生成多少个文件