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
}

原图

压缩图

SpringBoot+Nginx大文件传输的更多相关文章

  1. 大文件传输 分片上传 上传id 分片号 授权给第三方上传

    https://www.zhihu.com/question/39593108 作者:ZeroOne链接:https://www.zhihu.com/question/39593108/answer/ ...

  2. WCF大文件传输服务

    由于项目需要,自己写一个基于WCF的大文件传输服务雏形.觉得有一定的参考价值,因此放在网上分享. 目前版本为v1.1特点如下: 1.文件传输端口为18650 2.上传和下载文件 3.支持获取文件传输状 ...

  3. 转:wcf大文件传输解决之道(2)

    此篇文章主要是基于http协议应用于大文件传输中的应用,现在我们先解析下wcf中编码器的定义,编码器实现了类的编码,并负责将Message内存中消息转变为网络发送的字节流或者字节缓冲区(对于发送方而言 ...

  4. 转:wcf大文件传输解决之道(1)

    首先声明,文章思路源于MSDN中徐长龙老师的课程整理,加上自己的一些心得体会,先总结如下: 在应对与大文件传输的情况下,因为wcf默认采用的是缓存加载对象,也就是说将文件包一次性接受至缓存中,然后生成 ...

  5. WCF大文件传输【转】

    http://www.cnblogs.com/happygx/archive/2013/10/29/3393973.html WCF大文件传输 WCF传输文件的时候可以设置每次文件的传输大小,如果是小 ...

  6. 利用Socket进行大文件传输

    分类: WINDOWS 最近接触到利用socket进行大文件传输的技术,有些心得,与大家分享.首先看看这个过程是怎么进行的(如下图):      所以,我们需要三个socket在窗体加载的时候初始化: ...

  7. AetherUpload大文件传输

    AetherUpload-Laravel是laravel框架下的一个大文件传输组件 github:https://github.com/peinhu/AetherUpload-Laravel 文件传输 ...

  8. WCF大文件传输

    WCF传输文件的时候可以设置每次文件的传输大小,如果是小文件的时候,可以很方便的将文件传递到服务端,但是如果文件比较大的话,就不可取了 遇到大文件的话可以采取分段传输的方式进行文件传输 思路: 1.客 ...

  9. 基于WCF的支持跨局域网可断点续传的大文件传输服务实现

    题外话:这个系列的文章记录了本人最近写的一个小工程,主要包含了两个功能,一是对文件的断点续传的功能,二是基于WCF的一对多文件主动发送的功能,顺便这也是我自己在WCF学习路上的一个小成果吧. 在网上找 ...

  10. [源码]Python简易http服务器(内网渗透大文件传输含下载命令)

    Python简易http服务器源码 import SimpleHTTPServerimport SocketServerimport sysPORT = 80if len(sys.argv) != 2 ...

随机推荐

  1. MFC-error C2589: “(”:“::”右边的非法标记

    MFC-error C2589: "(":"::"右边的非法标记 错误信息 出错语句 问题原因 解决办法 错误信息 ① 错误 C2589 "(&quo ...

  2. docker和主机之间文件传输

    docker和主机之间文件传输 1.从docker内部向主机传输文件 语法: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- 示例:将容器96f7 ...

  3. Harbor 共享后端高可用

    1. 主机配置 主机地址 主机配置 主机角色 软件版本 192.168.1.60 CPU:4C MEM:4GB Disk: 100GB Harbor+Keepalived Harbor 2.1.3 K ...

  4. 【译】在分析器中使用 Meter Histogram(直方图)解锁见解

    您是否正在与应用程序中的性能瓶颈作斗争?不要再观望了!Visual Studio 2022 在其性能分析套件中引入了 Meter Histogram(直方图)功能,为您提供了前所未有的分析和可视化直方 ...

  5. LCR 164. 破解闯关密码

    破解闯关密码 闯关游戏需要破解一组密码,闯关组给出的有关密码的线索是: 一个拥有密码所有元素的非负整数数组 password 密码是 password 中所有元素拼接后得到的最小的一个数 请编写一个程 ...

  6. SequoiaDB数据库-new数据库

    随着企业中日益复杂与多变的需求,以及迅速扩展带来的海量数据的业务,IT部门需要将越来越多的信息提供给用户,同时在现今的全球经济背景环境下,IT部 门还需要在提供高效服务的同时,降低其设备与程序维护成本 ...

  7. openSSL学习-0

    本文记录openSSL密码库的学习. 首先推荐:openSSL中文手册 介绍 openssl是一个功能丰富且自包含的开源安全工具箱. 它提供的主要功能有:SSL协议实现(包括SSLv2.SSLv3和T ...

  8. C++:Boost库

    今日安装一个PSI库时,需要boost库,在此认识一下boost库,转载:macOS 中Boost的安装和使用 介绍 Boost是一个功能强大,构造精良,跨越平台,代码开源,完全免费的C++程序库. ...

  9. 探索魔乐社区:GLM-4V-9B模型微调之旅

    人工智能的浪潮中,魔乐社区以其丰富的资源和开放的环境,逐渐成为了开发者们的新宠.今天,让我们一起走进魔乐社区,通过GLM-4V-9B模型微调的最佳实践,体验这个平台的独特魅力. 多模态的新星:GLM- ...

  10. Q:windows server2019由于没有远程桌面授权服务器可以提供许可证,远程回话连接已断开

    由于没有远程桌面授权服务器可以提供许可证,远程回话连接已断开,请跟服务管理员联系 原因是服务器安装了远程桌面服务RemoteApp,这个是需要授权的.但是微软官方给予了120天免授权使用,超过120天 ...