当前位置: 首页 > news >正文

Spring Boot 实现图片上传并生成缩略图功能

在实际开发中,上传图片并生成缩略图是一项常见需求,例如在电商平台、社交应用等场景中,缩略图可以有效提高页面加载速度,优化用户体验。本文将介绍如何在 Spring Boot 项目中实现上传图片并生成缩略图的功能。

📦 1. 依赖配置

pom.xml 文件中添加以下依赖:

<!-- Spring Boot Web -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- 文件上传 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId>
</dependency><!-- 图片处理依赖 -->
<dependency><groupId>com.twelvemonkeys.imageio</groupId><artifactId>imageio-core</artifactId><version>3.8.1</version>
</dependency><!-- Apache Commons IO -->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.8.0</version>
</dependency>
📂 2. 核心代码实现

以下方法将实现图片上传并生成缩略图的功能:

import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;public String uploadPictureThumbnail(String bucketName, MultipartFile multipartFile, Long assocId, String originalStorageName, Integer scale, Integer width, Integer height) {String directoryPath = "";if (OsUtils.isLinux()) {directoryPath = "/tempdir";} else if (OsUtils.isWindows()) {directoryPath = "C:/tempdir";}File directory = new File(directoryPath);if (!directory.exists()) {directory.mkdir();}String originalName = multipartFile.getOriginalFilename();String suffixName = getSuffixName(originalName, ".", 0);String suffix = getSuffixName(originalName, ".", 1);String storageName = UUID.randomUUID().toString() + suffixName;String storageFileName = null;List<String> thumbnailSuffixName = Arrays.asList(".png", ".jpg", ".jpeg", ".gif");if (thumbnailSuffixName.contains(suffixName.toLowerCase())) {try {// 保存原始图片String originalImagePath = directoryPath + "/" + storageName;Path filePath = Paths.get(originalImagePath);Files.write(filePath, multipartFile.getBytes());// 读取原始图片并生成缩略图BufferedImage originalImage = ImageIO.read(new File(originalImagePath));int originalWidth = originalImage.getWidth();int originalHeight = originalImage.getHeight();// 计算缩略图尺寸int[] data = computeSize(originalWidth, originalHeight, scale, width, height);int thumbnailWidth = data[0];int thumbnailHeight = data[1];Image scaledImage = originalImage.getScaledInstance(thumbnailWidth, thumbnailHeight, Image.SCALE_SMOOTH);BufferedImage thumbnailImage = new BufferedImage(thumbnailWidth, thumbnailHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = thumbnailImage.createGraphics();g2d.drawImage(scaledImage, 0, 0, null);g2d.dispose();// 保存缩略图String thumbnailPath = directoryPath + "/" + UUID.randomUUID().toString() + suffixName;File thumbnailFile = new File(thumbnailPath);ImageIO.write(thumbnailImage, suffix.replace(".", ""), thumbnailFile);// 上传缩略图(这里用自定义 uploadFile 方法上传到对象存储)try (FileInputStream in = new FileInputStream(thumbnailFile)) {String name = getSuffixName(originalStorageName, "/", 1);storageFileName = uploadFile(bucketName, in, multipartFile.getContentType(), assocId, thumbnailFile.length(), name, "thumbnail");}// 清理临时文件new File(originalImagePath).delete();thumbnailFile.delete();} catch (IOException e) {e.printStackTrace();}}return storageFileName;
}
🔧 3. 计算缩略图尺寸方法

根据原始尺寸、比例、指定宽高生成合适的缩略图尺寸:

private int[] computeSize(int originalWidth, int originalHeight, Integer scale, Integer width, Integer height) {if (scale != null && scale > 0) {return new int[]{originalWidth * scale / 100, originalHeight * scale / 100};} else if (width != null && height != null) {return new int[]{width, height};} else {// 默认缩小为原始尺寸的 50%return new int[]{originalWidth / 2, originalHeight / 2};}
}
📝 4. 工具方法示例

用于提取文件后缀名:

private String getSuffixName(String fileName, String delimiter, int index) {String[] parts = fileName.split(delimiter);if (index < parts.length) {return delimiter + parts[parts.length - 1];}return "";
}
⚠️ 5. 注意事项
  1. 操作系统临时目录:根据不同操作系统,创建不同的临时文件夹路径。

  2. 文件清理:上传完成后及时删除临时文件,避免占用过多磁盘空间。

  3. 缩略图格式支持:目前支持 PNG、JPG、JPEG、GIF 格式。

  4. 上传逻辑uploadFile 方法需根据具体的存储服务(例如 MinIO、OSS、七牛云等)自定义实现。

🎯 6. 总结

通过以上步骤,我们成功实现了图片上传并生成缩略图的功能。此功能不仅能有效减少图片加载时间,还能节省存储空间,提升系统性能。如果你在实现过程中遇到问题,欢迎在评论区留言讨论!

相关文章:

Spring Boot 实现图片上传并生成缩略图功能

在实际开发中&#xff0c;上传图片并生成缩略图是一项常见需求&#xff0c;例如在电商平台、社交应用等场景中&#xff0c;缩略图可以有效提高页面加载速度&#xff0c;优化用户体验。本文将介绍如何在 Spring Boot 项目中实现上传图片并生成缩略图的功能。 &#x1f4e6; 1. …...

洛谷B3664[语言月赛202209] 零食售卖点

B3664 [语言月赛202209] 零食售卖点 - 洛谷 代码区&#xff1a; #include<bits/stdc.h>using namespace std;int main(){int n;cin >> n;int arry[n],dp[n];for(int i0;i<n;i){cin >> arry[i];}dp[0]0;sort(arry,arryn);for(int i1;i<n;i){dp[i]arry…...

贪心算法:JAVA从理论到实践的探索

在计算机科学领域,贪心算法是一种简单而高效的算法设计策略,广泛应用于优化问题的求解。它通过在每一步选择中都采取当前状态下最优的选择,以期望最终得到全局最优解。本文将深入探讨贪心算法的原理、应用场景,并通过具体代码示例,帮助读者更好地理解和掌握这一算法。 一…...

线程池10种常见坑

1. 直接使用 Executors 创建线程池 直接使用 Executors 提供的快捷方法&#xff1a; ExecutorService executor Executors.newFixedThreadPool(10);问题 无界队列&#xff1a;newFixedThreadPool 使用的队列是 LinkedBlockingQueue&#xff0c;它是无界队列&#xff0c;任务…...

鸿蒙ArkTs如何实现pdf预览功能?

鸿蒙ArkTs如何实现pdf预览功能&#xff1f; 前言PDFKit运行示例代码报错真机运行先看效果一、预览本地pdf文件二、预览线上的pdf文件三、预览沙箱目录中pdf的文件(重点)效果中的整体代码总结 Harmony OS NEXT版本&#xff08;接口及解决方案兼容API12版本或以上版本) 前言 在开…...

KylinSP3 | 防火墙和麒麟安全增强设置KySec

一、系统防火墙原理 麒麟操作系统从V10版本开始&#xff0c;默认使用了Firewalld防火墙&#xff0c;Firewalld是能提供动态管理的防火墙&#xff0c;支持网络/防火墙区域&#xff0c;用于定义网络连接或接口的信任级别。支持IPv4和IPv6防火墙设置、以太网桥接和IP集。将运行时…...

【C++】面试常问八股

5、内存管理 野指针 野指针指的是未进行初始化或未清零的指针&#xff0c;不是NULL指针野指针产生原因及解决方案&#xff1a; 指针变量未初始化&#xff1a;指针变量定义时若未初始化&#xff0c;则其指向的地址是随机的&#xff0c;不为NULL&#xff1b;定义时初始化为NULL…...

vscode多文件编译构建(CMake)和调试C++

目录 1. CMake 基础构建工具及作用相关配置文件 2. 配置 tasks.json关键字段详细解释 3. 配置 launch.json关键字段详细解释 4. 配置 CMakeLists.txt关键部分详细解释 5. 构建和调试项目1. 仅构建项目1.1 任务执行顺序1.2 cmake 任务执行详情1.3 build 任务执行详情1.4 构建后的…...

使用Docker 部署 LNMP+Redis 环境

使用Docker 部署 LNMPRedis 环境 Docker 简介 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互…...

文件上传漏洞学习笔记

一、漏洞概述 定义 文件上传漏洞指未对用户上传的文件进行充分安全校验&#xff0c;导致攻击者可上传恶意文件&#xff08;如Webshell、木马&#xff09;&#xff0c;进而控制服务器或执行任意代码。 危害等级 ⚠️ 高危漏洞&#xff08;通常CVSS评分7.0&#xff09;&#xff…...

375_C++_cloud手机推送,添加人脸告警信息到任务队列中,UploadAlarmPush是典型的工厂模式应用,为什么使用工厂模式完成这部分代码

一:AlarmFaceInfo的应用 让我帮你解析这个lambda表达式的实现: // ...................... .h ...........................// struct RsMsgPushTask_S : public Task{AlarmType_E mainAlarmType;unsigned int subAlarmType;DateTime alarmTime...

Spring Boot 中的日志管理

一、日志框架选择 1. 主流框架对比 框架特点Spring Boot 默认支持Logback- 性能优异&#xff0c;Spring Boot 默认集成- 支持自动热更新配置文件✅ (默认)Log4j2- 异步日志性能更强- 支持插件扩展- 防范漏洞能力更好❌ (需手动配置)JUL (JDK自带)- 无需额外依赖- 功能简单&am…...

火绒终端安全管理系统V2.0网络防御功能介绍

火绒终端安全管理系统V2.0 【火绒企业版V2.0】网络防御功能包含网络入侵拦截、横向渗透防护、对外攻击检测、僵尸网络防护、Web服务保护、暴破攻击防护、远程登录防护、恶意网址拦截。火绒企业版V2.0的网络防御功能&#xff0c;多层次、多方位&#xff0c;守护用户终端安全。 …...

海康摄像头 + M7s(Monibuca) + FFmpeg + Python实现多个网络摄像头视频流推流

最近在研究流媒体服务器时&#xff0c;我注意到了一款开源软件——M7s。按照官网的指南部署完成后&#xff0c;我开始进行测试&#xff0c;发现单视频流推送非常顺利&#xff0c;没有任何问题。然而&#xff0c;当我尝试进行多视频流推送时&#xff0c;却发现网上的相关教程寥寥…...

抖音视频如何下载保存去水印

随着短视频平台的兴起&#xff0c;抖音作为国内最受欢迎的短视频平台之一&#xff0c;吸引了大量用户上传和观看各种创意视频。许多用户在浏览抖音视频时&#xff0c;往往会想要保存一些有趣或精彩的视频片段&#xff0c;但抖音视频通常会有水印&#xff0c;影响观看体验。为了…...

【鸿蒙开发】第三十九章 LazyForEach:数据懒加载

目录 1 背景 2 使用限制 键值生成规则 组件创建规则 首次渲染 非首次渲染 改变数据子属性 使用状态管理V2 拖拽排序 1 背景 LazyForEach从提供的数据源中按需迭代数据&#xff0c;并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach&#xff0c;框架…...

HTTP-

一.HTTP 1.什么是HTTP HTTP(超文本传输协议)是一种工作在应用层的协议.主要用于网站,就是浏览器和服务器之间的数据传输. 小知识:什么是超文本传输协议 文本:是字符串.(能在utf8/gbk码表上找到合法字符) 超文本:不仅可以传输字符串,也可以传输图片,html等 富文本:word文档 2.HT…...

创建型模式 - 原型模式 (Prototype Pattern)

创建型模式 -原型模式 (Prototype Pattern) 它允许通过复制现有对象来创建新对象&#xff0c;而无需知道对象的具体创建细节。在 Java 中&#xff0c;可以通过实现 Cloneable 接口和重写 clone() 方法来实现原型模式。 有深、浅两种克隆 类实现 Cloneable 接口就可以深克隆如果…...

Android 8.0 (API 26) 对广播机制做了哪些变化

大部分隐式广播无法通过静态注册接收&#xff0c;除了以下白名单广播&#xff1a; ACTION_BOOT_COMPLETED ACTION_TIMEZONE_CHANGED ACTION_LOCALE_CHANGED ACTION_MY_PACKAGE_REPLACED ACTION_PACKAGE_ADDED ACTION_PACKAGE_REMOVED 需要以动态注册方案替换&#xff1a; cl…...

Unity汽车笔记

汽车的移动和转向 我们知道&#xff0c;汽车的前进后退是变速运动。按w&#xff0c;汽车开始加速&#xff0c;到最大速度后保持匀速&#xff0c;松开w&#xff0c;汽车受到阻力加速。如果按s减速&#xff0c;则以更大的加速度减速。后退反之。 按A/D时前轮偏转。只有前进后退…...

手把手教你用Verilog实现一个简易8点FFT:理解蝶形运算与旋转因子

从零实现8点FFT&#xff1a;Verilog硬件设计中的蝶形运算实战 在数字信号处理领域&#xff0c;快速傅里叶变换&#xff08;FFT&#xff09;堪称算法皇冠上的明珠。想象一下&#xff0c;当你面对一段音频波形或无线电信号时&#xff0c;如何快速识别其中隐藏的频率成分&#xff…...

终极解决方案:Dell笔记本风扇噪音快速搞定指南

终极解决方案&#xff1a;Dell笔记本风扇噪音快速搞定指南 【免费下载链接】DellFanManagement A suite of tools for managing the fans in many Dell laptops. 项目地址: https://gitcode.com/gh_mirrors/de/DellFanManagement 还在为Dell笔记本风扇噪音而烦恼吗&…...

避坑指南:瑞萨e2studio中DTC地址绑定的那些坑——以RA2E1内存操作为例

瑞萨RA2E1开发实战&#xff1a;DTC地址绑定疑难解析与高效调试方案 在嵌入式开发领域&#xff0c;瑞萨RA2E1系列MCU凭借其出色的低功耗特性和丰富的外设资源&#xff0c;成为物联网终端设备的理想选择。然而&#xff0c;当开发者深入使用e2studio集成开发环境时&#xff0c;往往…...

5分钟免费解锁Cursor AI Pro完整功能:开发者必备的高效解决方案

5分钟免费解锁Cursor AI Pro完整功能&#xff1a;开发者必备的高效解决方案 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached…...

STM32LL库实战入门:从零搭建高效开发环境

1. 为什么选择STM32 LL库开发&#xff1f; 第一次接触STM32 LL库的开发者可能会有疑问&#xff1a;已经有了HAL库和标准库&#xff0c;为什么还要学习LL库&#xff1f;这个问题要从嵌入式开发的效率需求说起。我在实际项目中遇到过这样的情况&#xff1a;使用STM32F030芯片做电…...

VS2019 MFC CEF(Chrome)集成实战:从环境配置到核心功能实现(含源码解析)

1. 为什么要在MFC中集成CEF&#xff1f; 十年前我刚接触MFC开发时&#xff0c;最头疼的就是界面美化问题。传统的GDI绘图方式要实现一个圆角按钮都得折腾半天&#xff0c;更别说复杂的动态效果了。直到发现CEF&#xff08;Chromium Embedded Framework&#xff09;这个神器&…...

实战指南:如何高效配置VcXsrv实现Windows与Linux图形应用无缝连接

实战指南&#xff1a;如何高效配置VcXsrv实现Windows与Linux图形应用无缝连接 【免费下载链接】vcxsrv VcXsrv Windows X Server (X2Go/Arctica Builds) 项目地址: https://gitcode.com/gh_mirrors/vc/vcxsrv 在跨平台开发工作中&#xff0c;开发者经常面临一个核心挑战…...

从样本到洞见:宏基因组数据分析全流程实战指南

1. 宏基因组数据分析入门&#xff1a;为什么你需要这份指南 第一次接触宏基因组数据分析的研究者&#xff0c;往往会陷入"数据海洋恐惧症"——面对数十GB的FASTQ文件&#xff0c;不知道该从哪里下手。我至今记得五年前处理第一个土壤样本时的场景&#xff1a;在服务器…...

Qwen2.5-VL 算法解析

Qwen2.5-VL 本质上是一个 Qwen2.5 LLM 原生动态分辨率 ViT 视觉到语言的 MLP 压缩器 面向图像/视频的时间对齐版 MRoPE 的统一多模态自回归模型。它相对 Qwen2-VL 的核心升级&#xff0c;不是简单“换了个更大的底座”&#xff0c;而是把 视觉编码效率、长视频时间建模、文档…...

从零实现:基于STM32的直流电机双闭环PID调速系统

1. 直流电机双闭环PID控制入门指南 第一次接触电机控制时&#xff0c;我被各种专业术语搞得晕头转向。直到亲手用STM32实现了双闭环PID调速系统&#xff0c;才发现原来核心原理可以这么简单理解。想象一下开车时的定速巡航&#xff1a;速度环就像你的右脚控制油门大小&#xf…...