首页 > 系统相关 >SpringBoot+Nginx大文件传输

SpringBoot+Nginx大文件传输

时间:2024-06-05 18:22:56浏览次数:23  
标签:SpringBoot 文件传输 upload fileStoreItem Nginx common new import String

Nginx配置

				# 公众端的附件上传
        location /api/visitor/upload {
            # Pass altered request body to this location
            upload_pass   /api/outerPortal/uploadAndSave;

            # Store files to this directory
            # The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist
            upload_store /home/museum/data/fileupload/upload/visitor 1;
            
            # Allow uploaded files to be read only by user
            upload_store_access user:rw;

            # Set specified fields in request body
            upload_set_form_field "${upload_field_name}_name" $upload_file_name;
            upload_set_form_field "${upload_field_name}_content_type" $upload_content_type;
            upload_set_form_field "${upload_field_name}_path" $upload_tmp_path;

            # Inform backend about hash and size of a file
            upload_aggregate_form_field "${upload_field_name}_md5" $upload_file_md5;
            upload_aggregate_form_field "${upload_field_name}_size" $upload_file_size;
			
			upload_pass_form_field ".*";
			upload_pass_form_field "modelName";

        }

        # Pass altered request body to a backend
        location /api/outerPortal/uploadAndSave {
           proxy_pass  http://10.130.1.11:8250;
        }

Springboot接口接受


package xxxx.museum.outerPortal.interfaces;

import xxxx.common.domain.model.Result;
import xxxx.common.domain.model.SessionUser;
import xxxx.museum.outerPortal.domain.model.FileStoreItemVisitor;
import xxxx.museum.outerPortal.service.UploadFileService;
import xxxx.visitor.common.VisitorBaseController;
import xxxx.visitor.common.domain.model.VisitorSessionUser;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 平台common文件上传暴露接口
 */
@RestController
@ConditionalOnClass(value = {org.thymeleaf.dialect.IExpressionObjectDialect.class})
@RequestMapping("api/outerPortal")
public class UploadController extends VisitorBaseController {

    @Autowired
    private UploadFileService uploadFileService;

    /**
     * 接收普通附件的上传
     */
    @PostMapping("/uploadAndSave")
    @ResponseBody
    @ApiOperation(value = "上传文件", notes = "用户文件上传")
    public Result uploadAndSave(@RequestParam(value = "modelName", required = false) String modelName,
                                @RequestParam(value = "files_name", required = false) String fileName,
                                @RequestParam(value = "files_path", required = false) String filePath,
                                @RequestParam(value = "files_size", required = false) Integer fileSize,
                                HttpServletRequest request,
                                HttpServletResponse reponse) {
        Result msg = new Result();
        msg.setSuccess(false);
        VisitorSessionUser sessionUser = getSessionUser(request);
        //将得到的用户对象
        SessionUser user = new SessionUser();
        user.setUserId(sessionUser.getMid());
        if (StringUtils.isNotEmpty(fileName)) {
            FileStoreItemVisitor itemVisitor = uploadFileService.save(sessionUser, modelName, fileName, filePath, fileSize);
            if (itemVisitor != null) {
                msg.setResponse(itemVisitor);
                msg.setMsg("上传头像成功!");
                msg.setSuccess(true);
            } else {
                msg.setMsg("上传失败,请重新上传!");
            }
        } else {
            msg.setMsg("上传失败,请重新上传!");
        }
        return msg;
    }


}

实现上传的机制

package xxxx.museum.outerPortal.service;

import cn.hutool.core.util.RuntimeUtil;
import com.alibaba.nacos.common.utils.UuidUtils;
import xxxx.common.domain.model.exception.BusinessException;
import xxxx.museum.outerPortal.domain.model.FileStoreItemVisitor;
import xxxx.visitor.common.domain.model.VisitorSessionUser;
import org.im4java.core.ConvertCmd;
import org.im4java.core.IMOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.Calendar;
import java.util.Date;

/**
 * @author Administrator
 * @apiNote 公众端文件上传
 * @date 2024/6/5 14:20
 */
@Service
@SuppressWarnings("all")
public class UploadFileService {
    private static String forbiddenExtension = "sh,bat,exe";

    private final String fileSaveBasePath = "/home/museum/data/fileupload/common/";

    private static String[] allowPictures = "bmp,jpeg,jpg,png".split(",");
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${visitor.html.base.path:http://10.130.1.11/fileupload/common/}")
    private String htmlBasePath;


    @Value("${visitor.image.magick.path:C:\\GraphicsMagick-1.3.36-Q16}")
    private String imageMagickPath;

    /**
     * 过滤有害脚本文件
     *
     * @param fileExt fileExt
     * @return boolean
     */
    private boolean checkFileExtension(String fileExt) {
        String[] forbiddenTypes = forbiddenExtension.split(",");
        String[] var3 = forbiddenTypes;
        int var4 = forbiddenTypes.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            String s = var3[var5];
            if (s.equalsIgnoreCase(fileExt)) {
                return false;
            }
        }

        return true;
    }

    public FileStoreItemVisitor save(VisitorSessionUser sessionUser, String modelName, String fileName, String filePath, Integer fileSize) {
        String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        if (!this.checkFileExtension(fileExtension)) {
            throw new BusinessException("不允许上传此类型文件:" + fileExtension);
        } else {
            // 年月日路径
            String relativePath = this.getRelativeFolder(fileSaveBasePath);
            // 生成本次文件移动的地址
            String folderPath = fileSaveBasePath + relativePath;
            // 生成文件名称
            String saveFileName = UuidUtils.generateUuid() + "." + fileExtension;
            // 生成全限定名称的文件声明
            String saveFilePath = folderPath + saveFileName;
            // Nginx Upload 文件 由暂存地址移动到当前路径全限定名
            String result = RuntimeUtil.execForStr(new String[]{"mv", filePath, saveFilePath});
            this.logger.info("文件移动结果:" + result);
            FileStoreItemVisitor fileStoreItem = new FileStoreItemVisitor();
            // 生成Nginx可访问的相对路径
            fileStoreItem.setRelativeUrl(relativePath);
            // 生成预览压缩图地址
            fileStoreItem.setThumbUrl(this.generateThumbnail(htmlBasePath, saveFilePath, fileExtension));
            logger.info("文件 Nginx 缩略图 路径:" + fileStoreItem.getThumbUrl());
            fileStoreItem.setFileName(fileName);
            fileStoreItem.setFileType(fileExtension);
            fileStoreItem.setFileSize(fileSize);
            fileStoreItem.setCreateTime(new Date());
            fileStoreItem.setCreatorId(sessionUser.getUserId());
            fileStoreItem.setCreator(sessionUser.getUserName());
            // 生成下载地址
            fileStoreItem.setHtmlUrl(htmlBasePath + relativePath + saveFileName);
            logger.info("文件 Nginx 下载 路径:" + fileStoreItem.getHtmlUrl());
            return fileStoreItem;
        }

    }

    private String generateThumbnail(String htmlBasePath, String filePath, String fileExtension) {
        String thumbnailUrl = "";
        if (this.isPicture(fileExtension)) {
            int idx = filePath.lastIndexOf(".");
            if (idx > -1) {
                String thumbnailPath = filePath.substring(0, idx) + "_thb." + fileExtension;
                this.compressImage(filePath, thumbnailPath, 300, 300, 0.8F);
                thumbnailUrl = htmlBasePath + thumbnailPath.replace(fileSaveBasePath, "");
            }
        } else {
            thumbnailUrl = "/static/global/img/file/" + fileExtension.toLowerCase() + ".png";
        }

        return thumbnailUrl;
    }


    public void compressImage(String imagePath, String thumbnailPath, int width, int height, Float quality) {
        IMOperation op = new IMOperation();
        op.addImage();
        String raw = width + "x" + height + "^";
        ConvertCmd cmd = new ConvertCmd(true);
        op.addRawArgs(new String[]{"-sample", raw});
        if (quality != null && !quality.toString().equals("")) {
            op.addRawArgs(new String[]{"-quality", quality.toString()});
        }
        op.addImage();
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.indexOf("win") != -1) {
            cmd.setSearchPath(imageMagickPath);
        } else {
            cmd.setSearchPath("/usr/local/bin");
        }

        try {
            cmd.run(op, new Object[]{imagePath, thumbnailPath});
        } catch (Exception var12) {
            this.logger.error("文件压缩失败", var12);
        }

    }

    boolean isPicture(String fileExtension) {
        String[] var2 = allowPictures;
        int var3 = var2.length;
        for (int var4 = 0; var4 < var3; ++var4) {
            String s = var2[var4];
            if (s.equalsIgnoreCase(fileExtension)) {
                return true;
            }
        }

        return false;
    }

    private String getRelativeFolder(String fileSavePath) {
        String relativePath = this.getFolderByDate();
        String path = fileSavePath + relativePath;
        File tempPath = new File(path);
        if (!tempPath.exists()) {
            tempPath.mkdirs();
        }
        return relativePath;
    }


    private String getFolderByDate() {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        builder.append(now.get(1)).append("/").append(now.get(2) + 1).append("/").append(now.get(5)).append("/");
        return builder.toString();
    }
}

结果

http://10.130.1.11/fileupload/common/2024/6/5/5694f15f-b345-4efd-a97e-4774dd38f467.xlsx
{
  "@type": "com.cztech.common.domain.model.Result",
  "msg": "上传头像成功!",
  "obj": {
    "@type": "com.cztech.museum.outerPortal.domain.model.FileStoreItemVisitor",
    "createTime": "2024-06-05 17:51:35",
    "creatorId": "2365",
    "fileName": "琴.jpeg",
    "fileSize": 95263,
    "fileType": "jpeg",
    "htmlUrl": "http://10.130.1.11/fileupload/common/2024/6/5/",
    "relativeUrl": "2024/6/5/",
    "thumbUrl": "http://10.130.1.11/fileupload/common//home/museum/data/fileupload/common/2024/6/5/724440db-d1af-48dc-a67a-5e124e78b566_thb.jpeg"
  },
  "response": {
    "@type": "com.cztech.museum.outerPortal.domain.model.FileStoreItemVisitor",
    "createTime": "2024-06-05 17:51:35",
    "creatorId": "2365",
    "fileName": "琴.jpeg",
    "fileSize": 95263,
    "fileType": "jpeg",
    "htmlUrl": "http://10.130.1.11/fileupload/common/2024/6/5/",
    "relativeUrl": "2024/6/5/",
    "thumbUrl": "http://10.130.1.11/fileupload/common/2024/6/5/724440db-d1af-48dc-a67a-5e124e78b566_thb.jpeg"
  },
  "success": true
}

image

原图

image

压缩图

image

标签:SpringBoot,文件传输,upload,fileStoreItem,Nginx,common,new,import,String
From: https://www.cnblogs.com/gtnotgod/p/18233543

相关文章

  • Java1.8语言+ springboot +mysql + Thymeleaf 全套家政上门服务平台app小程序源码
    Java1.8语言+springboot+mysql +Thymeleaf 全套家政上门服务平台app小程序源码家政系统是一套可以提供上门家政、上门维修、上门洗车、上门搬家等服务为一体的家政平台解决方案。它能够与微信对接、拥有用户端小程序,并提供师傅端app,可以帮助创业者在不需要相关技术人员及......
  • 如何从零开始创建一个完整的SpringBoot项目,逐步构建自己的技术栈。
     有的小伙伴虽然开发很多年,但是有很多连自己都没有动手去创建一个SpringBoot。原因各不相同,有的是开发项目比较忙,没有时间,刚去公司的时候项目的框架就是现成的,就一直用。还有就是自己没有闲下学习的习惯。我其实就是,最起码工作1-2的时候还没有自己创建过,当时自我学习的时间......
  • 基于SpringBoot的秒杀系统源码数据库
    基于SpringBoot的秒杀系统源码数据库社会发展日新月异,用计算机应用实现数据管理功能已经算是很完善的了,但是随着移动互联网的到来,处理信息不再受制于地理位置的限制,处理信息及时高效,备受人们的喜爱。本次开发一套基于SpringBoot的秒杀系统,管理员功能有个人中心,用户管理,商品类......
  • 基于springboot的二手车交易系统源码数据库
    基于springboot的二手车交易系统源码数据库如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统二手车交易信息管理难度大,容错率低,管理人员处理数据费工费时,所以专门为......
  • 基于springboot的纺织品企业财务管理系统源码数据库
    基于springboot的纺织品企业财务管理系统源码数据库在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对纺织品企业财务信息管理的提升,也为了对纺织品企业财务信息进行......
  • 一个基于 React + SpringBoot 的在线多功能问卷系统(附源码)
    简介:一个基于React+SpringBoot的在线多功能问卷系统前端技术栈:React、React-Router、Webpack、Antd、Zustand、Echarts、DnDKit后端技术栈:SpringBoot、MySQL、MyBatisPlus、Redis项目源码下载链接: https://pan.quark.cn/s/2e32786e0c61部分页面静态预览: 主要前......
  • nginx /Java 解决跨域问题方案
    location/{#if($request_method='OPTIONS'){#add_header'Access-Control-Allow-Origin''*';#add_header'Access-Control-Allow-Methods''GET,POST,OPTIONS';......
  • 基于springboot实现疫情信息管理系统项目【项目源码+论文说明】计算机毕业设计
    基于springboot实现疫情信息管理系统演示摘要近年来,信息化管理行业的不断兴起,使得人们的日常生活越来越离不开计算机和互联网技术。首先,根据收集到的用户需求分析,对设计系统有一个初步的认识与了解,确定疫情信息管理系统的总体功能模块。然后,详细设计系统的主要功能模块,通......
  • 03--nginx架构实战
    前言:这应该是nginx梳理的最后一章,写一些关于网站架构和网站上线的知识内容,主要是感觉到运维并不是单一方向的行业,这一章概念会有一些广泛,但是非常重要,都是这几年工作中遇到的情况,整理一下相关知识,遇到时可以直接按照目录寻找解决方案。1、动态网站简介当用户访问一个网站时,动......
  • 128springboot汽车租赁管理系统租车订单还车汽车资讯论坛管理(源码+文档+PPT+运行视频+
    项目技术:springboot+Maven+Vue等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows......