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. java通过apache poi框架读取2007版Excel文件

    java系读写excel文件既可以用jxl库,也可以用POI库,但是,jxl库只支持低版本的excel2003,不支持更高版本,无法直接输出*.xlsx文件,只能输出*.xls文件,另外,更新也不频繁 ...

  2. 不为人知的网络编程(十六):深入分析与解决TCP的RST经典异常问题

    本文由腾讯技术kernel分享,原题"TCP经典异常问题探讨与解决",下文进行了排版和内容优化等. 1.引言 TCP的经典异常问题无非就是丢包和连接中断,在这里我打算与各位聊一聊T ...

  3. 即时通讯技术文集(第38期):IM代码入门实践(Part2) [共15篇]

    为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第38 期. [- 1 -] 高仿Android版手机QQ首页侧滑菜单源码 [附件下载] [链接 ...

  4. .NET CORE 中用AutoMapper将实体转Dto

    .NET CORE 中用AutoMapper将实体转Dto 星速云 2019-08-31 10:06:02 193 收藏展开在开发过程中,经常会碰到数据实体对象(Entity)和数据传输对象(Dto) ...

  5. 如何快速的开发一个完整的iOS直播app(推流篇)

    开发一款直播app,肯定需要流媒体服务器,本篇主要讲解直播中流媒体服务器搭建,并且讲解了如何利用FFMPEG编码和推流,并且介绍了FFMPEG常见命令. 效果 一.安装Homebrew Homebre ...

  6. biancheng-Spring Cloud Alibaba Sentinel

    http://c.biancheng.net/springcloud/sentinel.html Sentinel 是由阿里巴巴中间件团队开发的开源项目,是一种面向分布式微服务架构的轻量级高可用流量控 ...

  7. Linux 提权指南

    知屋漏者在宇下,知政失者在草野,知经误者在诸子. 导航 壹 - 密码搜寻 贰 - Sudo 命令 叁 - SUID/SGID 特权 肆 - 计划任务 伍 - 文件/目录 陆 - Linux 内核 柒 ...

  8. 060_面向过程和面向对象区别 061_对象是什么_对象和数据管理 062_对象和类的关系_属性_成员变量_方法 063_一个典型类的写法和调用_类的UML图入门 064_内存分析详解_栈_堆_方法区_栈帧_程序执行的内存变化过程

    060_面向过程和面向对象区别 061_对象是什么_对象和数据管理 062_对象和类的关系_属性_成员变量_方法 public class SxtStu {//定义了一个类,包含的成员变量,属性,方法 ...

  9. Groove Intermediate pg walkthrough

    80端口web站点 dirsearch 没发现啥有用信息 感觉就是让我们突破登录框进后台的 https://github.com/ChurchCRM/CRM/issues/137 上网查到默认密码 登 ...

  10. HTML 基本骨架

    HTML 基本骨架 HTML5的骨架是构建HTML5页面的基础结构,它主要由以下几个部分组成: <!DOCTYPE html> <html> <head> < ...