从前端到后端全面解析文件上传

1.前端准备(vue+element-ui)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <link rel="stylesheet" href="./element-ui/lib/theme-chalk/index.css">
    <link rel="stylesheet" href="css/index.css">
    <script src="js/vue.js"></script>
    <script src="js/axios-0.18.0.js"></script>
    <script src="./element-ui/lib/index.js"></script>
    <style>
        .avatar-uploader .el-upload {
            border: 1px dashed #d9d9d9;
            border-radius: 6px;
            cursor: pointer;
            position: relative;
            overflow: hidden;
        }
        .avatar-uploader .el-upload:hover {
            border-color: #409EFF;
        }
        .avatar-uploader-icon {
            font-size: 28px;
            color: #8c939d;
            width: 178px;
            height: 178px;
            line-height: 178px;
            text-align: center;
        }
        .avatar {
            width: 178px;
            height: 178px;
            display: block;
        }
    </style>
</head>
<style>
</style>
<body>

<div id="app">
    <el-upload
            class="avatar-uploader"
            action="http://localhost:8088/members/upload"
            :show-file-list="false"
            :on-success="handleAvatarSuccess"
            :before-upload="beforeAvatarUpload">
        <img v-if="imageUrl" :src="imageUrl" class="avatar">
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        <p>{{name}}</p>
    </el-upload>
</div>

<script>
    new Vue({
        el: "#app",
        data() {
            return {
                imageUrl: '',
                name:'',
                url:'',
            };
        },
        methods: {
            handleAvatarSuccess(res, file) {
                this.imageUrl = URL.createObjectURL(file.raw);
                this.name=file.response.name
                this.url=file.response.url

                console.log(file)
            },
            beforeAvatarUpload(file) {
                const isLt2M = file.size / 1024 / 1024 < 10;

                if (!isLt2M) {
                    this.$message.error('上传头像图片大小不能超过 10MB!');
                }

                return isLt2M;
            }
        }
    })
</script>
</body>
</html>

2.后端准备(SpringBoot+minio+mysql)

2.1解决跨域

package com.data211.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @author rjj
 * @date 2023/2/3 - 15:15
 */
@Configuration
public class GlobalCorsConfig {
    /**
     * 允许跨域调用的过滤器
     */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        //允许白名单域名进行跨域调用(设置http://localhost:8080/ 表示指定请求源允许跨域)
        config.addAllowedOriginPattern("*");
        //允许跨越发送cookie
        config.setAllowCredentials(true);
        //放行全部原始头信息
        config.addAllowedHeader("*");
        //允许所有请求方法跨域调用
        config.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //指定拦截路径
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

2.2配置minio与mysql

pom依赖

		<dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.1</version>
        </dependency>

		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

		<!--第三方工具jar包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.17</version>
        </dependency>

配置文件配置

server:
  port: 8088

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: 
    username: root
    password: 

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
#  配置别名
  type-aliases-package: com.data211.pojo
  global-config:
    db-config:
#      主键自增长
      id-type: auto
#      表名前缀
      table-prefix: data211_
#      逻辑删除
      logic-delete-value: 1
      logic-not-delete-value: 0
#      控制台输出操作数据库日志
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

minio:
  endpoint: 
  accessKey: 
  secretKey: 
  bucket:
    files: 

配置minio客户端

package com.data211.config;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
  @author rjj
  @date 2023/2/18 - 17:37
*/
@Configuration
public class MinioConfig {
    @Value("${minio.endpoint}")
    private String endpoint;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;

    @Bean
    public MinioClient minioClient() {
        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint(endpoint)
                        .credentials(accessKey, secretKey)
                        .build();
        return minioClient;
    }
}

2.3controller层

  @RequestMapping(value = "/upload")
    public UploadFileResultDto upload(@RequestPart("file") MultipartFile file) throws IOException {
        return membersService.upload(file);
    };

2.4service层

package com.data211.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.data211.dao.MembersDao;
import com.data211.dto.UploadFileResultDto;
import com.data211.pojo.MediaFiles;
import com.data211.pojo.Members;
import com.data211.service.IMembersService;
import com.data211.utils.BaseContext;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class MembersServiceImpl extends ServiceImpl<MembersDao, Members> implements IMembersService {

    @Resource
    private MinioClient minioClient;
    //普通文件桶
    @Value("${minio.bucket.files}")
    private String bucket_Files;

    @Resource
    private MembersServiceImpl membersService;

    @Resource
    private MediaFilesServiceImpl mediaFilesService;

    @Override
    public UploadFileResultDto upload(MultipartFile file) throws IOException {

        String fileMd5 = DigestUtil.md5Hex(file.getBytes());
        String folder = getFileFolder(new Date(), true, true, true);
        String filename = fileMd5+file.getName().substring(file.getName().lastIndexOf("."));

        MediaFiles mediaFiles = null;
        try {

            //TODO 上传到minio
            addMediaFilesToMinIO(file, bucket_Files, folder+filename);

            //TODO 上传到数据库 (用Spring控制的代理对象实现事务控制生效)
            mediaFiles = membersService.addMediaFilesToDb(BaseContext.getUserId(),filename,folder+filename);

            UploadFileResultDto uploadFileParamsDto = new UploadFileResultDto();
            BeanUtils.copyProperties(mediaFiles,uploadFileParamsDto);
            return uploadFileParamsDto;

        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }

    @Override
    @Transactional
    public MediaFiles addMediaFilesToDb(String userId, String filename,String url) {
        MediaFiles mediaFiles = new MediaFiles(userId, filename, url);
        mediaFilesService.save(mediaFiles);
        return mediaFiles;
    }


    public void addMediaFilesToMinIO(MultipartFile file, String bucket, String objectName) throws IOException {
        //  将文件字节输入到内存流中
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(file.getBytes());
        //获取文件类型
        String contentType = file.getContentType();
        try {
            PutObjectArgs putObjectArgs =
                    PutObjectArgs.builder().bucket(bucket).object(objectName)
                            //-1 表示文件分片按 5M(不小于 5M,不大于 5T),分片数量最大10000
                            .stream(byteArrayInputStream, byteArrayInputStream.available(), -1)
                            .contentType(contentType)
                            .build();
            minioClient.putObject(putObjectArgs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private String getFileFolder(Date date, boolean year, boolean month, boolean day) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //获取当前日期字符串
        String dateString = sdf.format(new Date());
        //取出年、月、日
        String[] dateStringArray = dateString.split("-");
        StringBuffer folderString = new StringBuffer();
        if (year) {
            folderString.append(dateStringArray[0]);
            folderString.append("/");
        }
        if (month) {
            folderString.append(dateStringArray[1]);
            folderString.append("/");
        }
        if (day) {
            folderString.append(dateStringArray[2]);
            folderString.append("/");
        }
        return folderString.toString();
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值