SpringBoot入门—文件上传

2024-07-02  本文已影响0人  遇见编程

1.简介

前端代码:

<form action="/upload" method="post" enctype="multipart/form-data">
    姓名: <input type="text" name="username"><br>
    年龄: <input type="text" name="age"><br>
    头像: <input type="file" name="image"><br>
    <input type="submit" value="提交">
</form>

MultipartFile 常见方法:

  • String getOriginalFilename(); //获取原始文件名
  • void transferTo(File dest); //将接收的文件转存到磁盘文件中
  • long getSize(); //获取文件的大小,单位:字节
  • byte[] getBytes(); //获取文件内容的字节数组
  • InputStream getInputStream(); //获取接收到的文件内容的输入流

后端代码:

@Slf4j
@RestController
public class UploadController {

    @PostMapping("/upload")
    public Result upload(String username, Integer age, MultipartFile image)  {
        log.info("文件上传:{},{},{}",username,age,image);
        return Result.success();
    }

}

问题:如果表单项的名字和方法中形参名不一致,该怎么办?
解决:使用@RequestParam注解进行参数绑定

public Result upload(String username, Integer age,  @RequestParam("image") MultipartFile file)

当我们程序运行完毕之后,这个临时文件会自动删除。

所以,我们如果想要实现文件上传,需要将这个临时文件,要转存到我们的磁盘目录中。

1.本地存储

保证每次上传文件时文件名都唯一的(使用UUID获取随机文件名)

@Slf4j
@RestController
public class UploadController {

    @PostMapping("/upload")
    public Result upload(String username, Integer age, MultipartFile image) throws IOException {
        log.info("文件上传:{},{},{}",username,age,image);

        //获取原始文件名
        String originalFilename = image.getOriginalFilename();

        //构建新的文件名
        String extname = originalFilename.substring(originalFilename.lastIndexOf("."));//文件扩展名
        String newFileName = UUID.randomUUID().toString()+extname;//随机名+文件扩展名

        //将文件存储在服务器的磁盘目录
        image.transferTo(new File("E:/images/"+newFileName));

        return Result.success();
    }
}

在SpringBoot中,文件上传时默认单个文件最大为1M
如果需要上传大文件,可以在application.properties进行如下配置:

#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB

#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB

其他方式:

/**
 * 文件上传
 */
@RestController
public class FileController {

    //绑定文件上传路径到uploadPath
    @Value("${web.upload-path}")
    private String uploadPath;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");

    @PostMapping("/api/file/upload")
    public BaseResponse upload(@Param("file") MultipartFile file, HttpServletRequest request) {
        BaseResponse response = BaseResponse.successResponse();
        DownFileRest rest = new DownFileRest();

        String format = sdf.format(new Date());
        File folder = new File(uploadPath + format);
        if (!folder.isDirectory()) {
            folder.mkdirs();
        }
        // 对上传的文件重命名,避免文件重名
        String oldName = file.getOriginalFilename();
        String newName = UUID.randomUUID() + oldName.substring(oldName.lastIndexOf("."), oldName.length());
        try {
            // 文件保存
            file.transferTo(new File(folder, newName));

            // 返回上传文件的访问路径
            String filePath = request.getScheme() + "://" + request.getServerName()
                    + ":" + request.getServerPort()  +"/"+ format + newName;
            System.out.println(filePath);

            rest.setFileUrl(filePath);
            rest.setName(newName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return response.setData(rest);
    }
}

application.yml

spring:
  profiles:
    active: dev
  servlet:
    multipart:
      # 单个文件的最大值
      max-file-size: 100MB
      # 传文件总的最大值
      max-request-size: 1024MB
  jackson:
    default-property-inclusion: non_null
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .apk
server:
  port: 8081

# mybatis-plus
mybatis-plus:
  mapper-locations: classpath:**/mapper/*Mapper.xml

application-dev.yml

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
  web:
    resources:
      static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${web.upload-path}
server:
  port: 8081

logging:
  config: classpath:logback.xml

web:
  upload-path: G:/data/

2.阿里云OSS

<!--阿里云OSS-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
</dependency>

测试类

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;

import java.io.FileInputStream;
import java.io.InputStream;

public class AliOssTest {
    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "oss-cn-beijing.aliyuncs.com";

        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = "LTAI5tSZXgUGdj6fSGHyPu4T";
        String accessKeySecret = "PiBcNmWlZZRRW0yp4E1Q2fSB9gjwEt";

        // 填写Bucket名称,例如examplebucket。
        String bucketName = "java-web-test-001";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "1.jpg";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "C:\\Users\\Public\\Pictures\\1.jpg";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            InputStream inputStream = new FileInputStream(filePath);
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 设置该属性可以返回response。如果不设置,则返回的response为空。
            putObjectRequest.setProcess("true");
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            // 如果上传成功,则返回200。
            System.out.println(result.getResponse().getStatusCode());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

工具类

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

@Component
public class AliOSSUtils {
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile multipartFile) throws IOException {
        // 获取上传的文件的输入流
        InputStream inputStream = multipartFile.getInputStream();

        // 避免文件覆盖
        String originalFilename = multipartFile.getOriginalFilename();
        String fileName = null;
        if (originalFilename != null) {
            fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
        }

        //上传文件到 OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.putObject(bucketName, fileName, inputStream);

        //文件访问路径
        String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;

        // 关闭ossClient
        ossClient.shutdown();
        return url;// 把上传到oss的路径返回
    }
}

aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    accessKeyId: LTAI5txxxxxxxxxxxxxxxxxx
    accessKeySecret: PiBcxxxxxxxxxxxxxxxxxxxx
    bucketName: java-web-xxxxxxxx
package com.hjy.controller;

import com.hjy.pojo.Result;
import com.hjy.utils.AliOSSUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Slf4j
@RestController
public class UploadController {

    @Autowired
    private AliOSSUtils aliOSSUtils;

    /**
     * 上传本地
     * @return
     * @throws IOException
     */
    @PostMapping("/uploadLocal")
    public Result uploadLocal(String username, Integer age, MultipartFile image) throws IOException {
        log.info("文件上传:{},{},{}",username,age,image);

        //获取原始文件名
        String originalFilename = image.getOriginalFilename();

        //构建新的文件名
        String extname = null;//文件扩展名
        if (originalFilename != null) {
            extname = originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        String newFileName = UUID.randomUUID() +extname;//随机名+文件扩展名
        //将文件存储在服务器的磁盘目录
        image.transferTo(new File("E:/images/"+newFileName));

        return Result.success();
    }


    @PostMapping("/upload")
    public Result uploadOSS(MultipartFile image) throws IOException {
        //调用阿里云OSS工具类,将上传上来的文件存入阿里云
        String url = aliOSSUtils.upload(image);
        //将图片上传完成后的url返回,用于浏览器回显展示
        return Result.success(url);
    }
}

其他方法:

@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss.file")
public class OssProperties {
    private String endPoint;
    private String keyId;
    private String keySecret;
    private String bucketName;
}
import org.springframework.web.multipart.MultipartFile;

public interface FileService {

    /**
     * 删除文件
     *
     * @param url
     */
    void deleteFile(String url);

    /**
     * 文件上传
     *
     * @param file   文件上传对象
     * @param module 文件夹名称
     * @return
     */
    String upload(MultipartFile file, String module);
}
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.hjy.config.oss.OssProperties;
import com.hjy.service.FileService;
import org.apache.commons.io.FilenameUtils;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

@Service
@Transactional
public class FileServiceImpl implements FileService {
    /**
     * 文件上传
     *
     * @param file 文件上传对象
     * @param module 文件夹名称
     * @return
     */
    @Resource
    private OssProperties ossProperties;

    /**
     * 文件上传
     *
     * @param file   文件上传对象
     * @param module 文件夹名称
     * @return
     */
    @Override
    public String upload(MultipartFile file, String module) {
        //获取地域节点
        String endPoint = ossProperties.getEndPoint();
        //获取AccessKeyId
        String keyId = ossProperties.getKeyId();
        //获取AccessKeySecret
        String keySecret = ossProperties.getKeySecret();
        //获取BucketName
        String bucketName = ossProperties.getBucketName();
        try {
            //创建OSSClient实例
            OSS ossClient = new OSSClientBuilder().build(endPoint, keyId, keySecret);
            //上传文件流
            InputStream inputStream = file.getInputStream();
            //获取旧名称
            String originalFilename = file.getOriginalFilename();
            //获取文件后缀名
            String extension = FilenameUtils.getExtension(originalFilename);
            //将文件名重命名
            String newFileName = UUID.randomUUID().toString().replace("-", "") + "." + extension;
            //使用当前日期进行分类管理
            String datePath = new DateTime().toString("yyyy/MM/dd");
            //构建文件名
            newFileName = module + "/" + datePath + "/" + newFileName;
            //调用OSS文件上传的方法
            ossClient.putObject(bucketName, newFileName, inputStream);
            //关闭OSSClient
            ossClient.shutdown();
            //返回文件地址

            //endPoint---https://oss-cn-beijing.aliyuncs.com
            //bucketName---java-web-test-001
            return "https://" + bucketName + "." + endPoint.split("//")[1] + "/" + newFileName;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void deleteFile(String url) {
        //https://java-web-test-001.oss-cn-beijing.aliyuncs.com/avatar/2024/06/15/20aaa46600364de78bcd1637f146c103.jpg
        //获取地域节点
        String endPoint = ossProperties.getEndPoint();
        //获取AccessKeyId
        String keyId = ossProperties.getKeyId();
        //获取AccessKeySecret
        String keySecret = ossProperties.getKeySecret();
        //获取BucketName
        String bucketName = ossProperties.getBucketName();
        try {
            //创建OSSClient实例
            OSS ossClient = new OSSClientBuilder().build(endPoint, keyId, keySecret);
            //组装文件地址
            String host = "https://" + bucketName + "." + endPoint.split("//")[1] + "/";
            //获取文件名称
            String objectName = url.substring(host.length());
            //删除文件
            ossClient.deleteObject(bucketName, objectName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

@RestController
@RequestMapping("/api/oss/file")
public class OSSController {

    @Resource
    private FileService fileService;

    /**
     * 文件上传
     *
     * @param file
     * @param module
     * @return
     */
    @PostMapping("/upload")
    public Result upload(MultipartFile file, String module) {
        //返回上传到oss的路径
        String url = fileService.upload(file, module);
        return Result.ok(url).message("文件上传成功");
    }
}

上一篇下一篇

猜你喜欢

热点阅读