概述场景

文件上传,是程序开发中必须会使用到的一个功能,比如:

  • 添加商品,用户头像,文章封面等需求
  • 富文本编辑(插件文件上传)

文件上传的原理是什么?

我们为什么要实现文件上传,其实就要共享资源,大家都可以看你的在平台上上传的文件;其实就是把用户自己电脑中的文件,通过程序上传到服务器的过程。

java阿里oss上传文件设置有效期 oss 文件上传_spring


总结一下:把用户的文件javaIO流复制到服务器上的过程,称之为文件上传。

用springboot实现文件上传

实现步骤

1.搭建一个springboot项目

2.准备一个页面上传的页面

在resources/templates/upload.html

server:
  port: 8777

spring:
  freemarker:
    suffix: .html
    cache: false

3、实现后台的文件上传

定义文件上传的service

package com.ygt.service;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

/**
 * @Author ygt
 * @Date 2022/9/21 18:50
 * @Version 1.0
 */

@Service
public class UploadService {

    /**
     * MultipartFile 这个对象是springMvc提供的文件上传的接收的类,
     * 他的底层会去和HttpServletRequest request 中的request.getInputStream()融合
     * 从而达到文件上传的效果。也就是说:
     * 文件上传的原理就是:request.getInputStream()
     * @param multipartFile
     * @param dir
     * @return
     */

    public String uploadImg(MultipartFile multipartFile,String dir){
        //1.指定文件上传的目录
        File targetFile = new File("D://tmp/" + dir);
        try {
            if(!targetFile.exists())targetFile.mkdirs();
            //2.指定文件上传以后的目录
            File targetFileName = new File(targetFile,"aaa.png");
            //3.文件上传到指定的目录
            multipartFile.transferTo(targetFileName);
            return "ok";
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }
    }
}

定义一个文件上传的controller

package com.ygt.controller;

import com.ygt.service.UploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author ygt
 * @Date 2022/9/21 18:49
 * @Version 1.0
 */
@Controller
public class UploadController {

    @Autowired
    private UploadService uploadService;

    /**
     * 文件上传的具体实现
     * @param multipartFile
     * @param request
     * @return
     */

    @PostMapping("/upload/file")
    @ResponseBody
    public String upload(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request){
        if(multipartFile.isEmpty()){
            return "文件有误!!";
        }

        //1:获取用户指定的文件夹。问这个文件夹为什么要从页面上传过来呢?
        //原因是:做隔离,不同的业务、不同的文件放在不同的目录中
        String dir = request.getParameter("dir");

        return uploadService.uploadImg(multipartFile,dir);
    }
}

定义一个页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>

    <h1>文件上传</h1>

    <form action="/upload/file" enctype="multipart/form-data" method="post">
        <input name="dir" value="bbs">
        <input name="file" type="file">
        <input type="submit" value="文件上传">
    </form>
</body>
</html>

java阿里oss上传文件设置有效期 oss 文件上传_java_02

点击文件上传,在后台看到如下代码:

java阿里oss上传文件设置有效期 oss 文件上传_spring_03

springMvc中对文件上传提供了包装对象:MultipartFile 原理如下:

  • 通过MultipartFile 我们可以很清楚的看到,文件已经被服务器接收
  • 但是会产生一个临时目录,这个目录是可以去配置的

文件上传不会直接上传至实际目录,它一定要经过一个临时目录的中转以后,才会上传到真实目录,其作用为:

  • 防止上传出现网络断开,或者用户上传直接刷新或者取消。因为如果用户的网络断开或者取消,就造成大量的垃圾文件
  • 保证真实目录上传的文件一定是有效的
  • 文件上传的大小:可以进行配置的
  • 文件上传的类型:也是可以进行配置的
server:
  port: 8777

spring:
  freemarker:
    suffix: .html
    cache: false

  servlet:
    multipart:
      enabled: true
      # 单个文件大小 默认1M
      max-file-size: 1MB
      # 设置总上传文件的数据大小
      max-request-size: 10MB
      # 当文件达到多少时进行磁盘写入
      file-size-threshold: 20MB
      # 设置临时目录
      location: D://tmp//tempxxx

4、指定文件上传的目录

  • 配置springboot静态资源存储服务,将上传的文件放入指定的目录中
package com.ygt.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @Author ygt
 * @Date 2022/9/21 18:50
 * @Version 1.0
 */

@Service
public class UploadService {

    @Value("${file.uploadFolder}")
    private String uploadFolder;
    @Value("${file.staticPath}")
    private String staticPath;

    /**
     * MultipartFile 这个对象是springMvc提供的文件上传的接收的类,
     * 他的底层会去和HttpServletRequest request 中的request.getInputStream()融合
     * 从而达到文件上传的效果。也就是说:
     * 文件上传的原理就是:request.getInputStream()
     * @param multipartFile
     * @param dir
     * @return
     */

    public String uploadImg(MultipartFile multipartFile,String dir){
        try {
            String realfilename = multipartFile.getOriginalFilename();  //  上传的文件:aaa.jpg
            //2.截取文件名的后缀
            String imgSuffix = realfilename.substring(realfilename.lastIndexOf("."));   //  拿到:.jpg
            //3.生成唯一的文件名,不能用中文命名,统一用英文名命名
            String newFilename = UUID.randomUUID().toString() + imgSuffix;  //  将aaa.jpg改写成:SDJFSDK3424.jpg
            //4.日期目录
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
            String datePath = dateFormat.format(new Date());    // 日期目录:2022/9/25
            //5.指定文件上传以后的目录
            String serverpath = uploadFolder; //这不是tomcat服务目录,别人不认识

            File targetPath = new File(serverpath+dir,datePath); //生成一个最终目录:D://tmp/avatar/2022/9/25
            if(!targetPath.exists())targetPath.mkdirs(); //如果目录不存在:D://tmp/avatar/2022/9/25 递归创建
            //6.指定文件上传以后的服务器的完整的文件名
            File targetFileName = new File(targetPath,newFilename); //文件上传以后在服务器上最终文件名和目录是:D://tmp/avatar/2022/9/25/SDJFSDK3424.jpg
            //7.文件上传到指定的目录
            multipartFile.transferTo(targetFileName); //将用户选择的aaa.jpg上传到D://tmp/avatar/2022/9/25/SDJFSDK3424.jpg


            // 可访问的路径要返回页面
            // http://localhost:8777/avatar/2022/9/25/SDJFSDK3424.jpg
            String filename = dir+"/"+datePath+"/"+newFilename;
            return staticPath+"/"+filename;
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }
    }
}

5、通过http请求服务资源

springboot如何指定任意目录作为我们资源的访问目录?

springboot有一个目录:static这个目录其实就是静态资源目录,这个目录下面的文件是是可以通过http直接访问的。但是程序化一般是打成jar包的,我们没办法把文件写入到static下,所以springboot提供静态资源目录的额外的映射机制,就是静态资源服务映射。就类似于:nginx的静态资源映射。

package com.ygt.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author ygt
 * @Date 2022/9/29 1:04
 * @Version 1.0
 */

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Value("${file.staticPatternPath}")
    private String staticPatternPath;
    @Value("${file.uploadFolder}")
    private String uploadFolder;


    // 这个就是springboot中springMvc让程序开发者去配置文件上传的额外的静态资源服务的配置
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(staticPatternPath).addResourceLocations("file:"+uploadFolder);
        // 跳转到出文件名前缀需要加上http://localhost:8777/uploadimg/


    }
}

核心代码分析:

registry.addResourceHandler("访问的路径").addResourceLocations("上传资源的路径");
registry.addResourceHandler("/uploadimg").addResourceLocations("file:D://tmp");

这个时候你把:aaa.png文件上传到了D://tmp下,那么:你可以通过:http:localhost:8777/uploadimg/aaa.png

环境隔离配置:

application-dev.yml

# 本机配置
file:
  staticPath: http://localhost:8777
  staticPatternPath: /upimages/**
  uploadFolder: D:/tmp/

application-prod.yml

# 服务器配置
file:
  staticPath: https://www.kuangstudy.com
  staticPatternPath: /upimages/**
  uploadFolder: /www/upload/

application.yml激活环境

server:
  port: 8777

spring:
  freemarker:
    suffix: .html
    cache: false
  profiles:
    active: dev

  servlet:
    multipart:
      enabled: true
      # 单个文件大小 默认1M
      max-file-size: 5MB
      # 设置总上传文件的数据大小
      max-request-size: 10MB
      # 当文件达到多少时进行磁盘写入
      file-size-threshold: 20MB
      # 设置临时目录
      location: D://tmp//tempxxx

6、对文件上传的思考和优化和控制

  • 比如文件的格式
  • 比如文件的大小
  • 比如文件的重命名
  • 比如文件的目录分类

以上就是我关于使用阿里云OSS实现文件上传的全部思路了,希望这篇文章能对屏幕前的你有所帮助。