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

Springboot 3 上传图片,并返回路径让前端显示图片

将图片存储在本地数据库中,通过访问后端的静态资源地址来访问图片

整体流程

  1. 通过接口上传文件(MultipartFile本质上是输入流)
  2. 对内容进行校验
  3. 将输入流转变为字节数组,确保可重复使用
  4. 转换图片格式
  5. 对图片进行保存和数据库中路径的存储

一、基本代码

代码中的路径尽量使用Paths.get 方法去拼接,而不是直接使用字符串拼接。

Controller层

@PostMapping("/uploadAvatar")public BaseResponse<String> uploadAvatar(@RequestParam MultipartFile file, Long userId) throws IOException {var fileInput = new BufferedInputStream(file.getInputStream());var result = fileService.uploadAvatar(fileInput, userId);return ResultUtils.success(result);}

MultipartFile类不能使用@RequestBody注解

  • @RequestBody:用于将请求体内容反序列化为Java对象,通常处理JSON或XML格式的数据

  • MultipartFile:用于处理文件上传,属于multipart/form-data格式,而不是JSON/XML

Validator校验类

使用了@Component注解

public File avatarValidator(BufferedInputStream fileInput, Long userId) throws IOException {if (!Objects.nonNull(fileInput) || !Objects.nonNull(userId)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");}var queryWrapper = new QueryWrapper();queryWrapper.eq(User::getId, userId);var user = userService.getOne(queryWrapper);if (!Objects.nonNull(user)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");}
//        if (!Objects.nonNull(ImageIO.read(fileInput))) {
//            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请上传图片类型文件");
//        }byte[] fileBytes = IoUtil.readBytes(fileInput);final int MAX_SIZE = 10 * 1024 * 1024;if (fileBytes.length > MAX_SIZE) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件过大,图片大小不超过10MB");}var image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);try {image = ImgUtil.read(IoUtil.toStream(fileBytes));File tempFile = File.createTempFile("image-", ".jpg");BufferedImage jpgImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);Graphics2D g2d = jpgImage.createGraphics();g2d.setColor(Color.WHITE);g2d.fillRect(0, 0, image.getWidth(), image.getHeight());g2d.drawImage(image, 0, 0, null);g2d.dispose();ImgUtil.write(jpgImage, tempFile);return tempFile;} catch (IOException e) {throw new BusinessException(ErrorCode.OPERATION_ERROR, "图片转换失败");}}
  • 在使用一次输入流之后,再访问这个对象会失效,正确的方式需要将其转变为2进制对象。才能做到多次使用。
  • 二进制对象再变为图片时如果尺寸大于图片的原尺寸,则会出现白色(或黑色)多余内容,请使用ai自行解决。

Impl实现类

@Overridepublic String  uploadAvatar(BufferedInputStream fileInput, Long userId) throws IOException {var image = valid.avatarValidator(fileInput,userId);var extName = FileUtil.extName(image);if (!FileUtil.exist(properties.getUploadBaseDir())){FileUtil.mkdir(properties.getUploadBaseDir());}var currentDate = DateUtil.today();var rand = IdUtil.simpleUUID();var fileName = currentDate + "-" + rand + "." + extName;var IMAGE_PATH = Paths.get("images/avatar", fileName).toString();var queryWrapper = new QueryWrapper();queryWrapper.eq(User::getId,userId);var user = userService.getOne(queryWrapper);if (Objects.nonNull(user.getAvatar())){var oldPath = Paths.get(properties.getUploadBaseDir(),user.getAvatar());var fileQuery = new QueryWrapper();fileQuery.eq(File::getPath,user.getAvatar());var oldFile = this.getOne(fileQuery);this.removeById(oldFile);FileUtil.del(oldPath);}var saveFile = new java.io.File(Paths.get(properties.getUploadBaseDir(), IMAGE_PATH).toString());FileUtil.copy(image.toPath(), saveFile.toPath());//上传新文件user.setAvatar(IMAGE_PATH);userService.updateById(user);image.deleteOnExit();var fileSize = (int)image.length()/1024;var file =new File();file.setType("avatar");file.setPath(IMAGE_PATH);file.setSize( fileSize);file.setCreateId(userId);this.save( file);return IMAGE_PATH;}

二、配置静态资源处理器


public class CorsConfig implements WebMvcConfigurer {private final FileConfig config;public CorsConfig(FileConfig config) {this.config = config;}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {Path avatarDir = Paths.get(config.getUploadBaseDir(), "images/avatar");String normalizedPath = avatarDir.toAbsolutePath().toString().replace("\\", "/");String resourcePath = "file:" + normalizedPath + "/";registry.addResourceHandler("/images/avatar/**").addResourceLocations(resourcePath).setCachePeriod(3600);}
}

三、配置类

@Component
@ConfigurationProperties(prefix = "file.image")
@Data
public class FileConfig {private String uploadBaseDir;
}

在applicaiton.yml或者application.properties中添加自己的路径配置。

#文件上传路径
file:image:upload-base-dir: doc/

四、扩展

图片后续可以存入cos或者使用minIO进行存储,而不是存在本地。

五、前端展示

接口

export async function uploadAvatar(// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)params: API.uploadAvatarParams,body: {},options?: { [key: string]: any }
) {return request<API.BaseResponseString>('/file/uploadAvatar', {method: 'POST',params: {...params,},data: body,...(options || {}),})
}

接口不要添加请求头,不是json的格式

headers: {'Content-Type': 'application/json',},

图片地址

localhost:{后端端口}/{avatarPath}     //avatarPath为后端数据库中存储的路径

http://www.dtcms.com/a/338779.html

相关文章:

  • 《UE5_C++多人TPS完整教程》学习笔记43 ——《P44 奔跑混合空间(Running Blending Space)》
  • 监督分类——最小距离分类、最大似然分类、支持向量机
  • Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
  • BROADCHIP广芯电子在各类电子产品的方案与应用
  • 3、栈和队列
  • Ansible 配置并行 - 项目管理笔记
  • 零知开源——基于STM32F407VET6与GY-271三轴地磁传感器的高精度电子罗盘设计与实现
  • TensorFlow 面试题及详细答案 120道(11-20)-- 操作与数据处理
  • Auto-CoT:大型语言模型的自动化思维链提示技术
  • OpenCV快速入门(C++版)
  • 常见的 Bash 命令及简单脚本
  • 从 0 到 1 开发校园二手交易系统:飞算 JavaAI 全流程实战
  • 无畏契约手游上线!手机远控模拟器畅玩、抢先注册稀有ID!
  • Windows/Centos 7下搭建Apache服务器
  • MySQL-分库分表(Mycat)
  • 第一章 认识单片机
  • 出现了常规系统错误: Unable to push signed certificate to host 192.168.1.2
  • 从数据表到退磁:Ansys Maxwell中N48磁体磁化指南
  • LINUX 软件编程 -- 线程
  • 决策树的学习(二)
  • MCP(模型上下文协议):是否是 AI 基础设施中缺失的标准?
  • jsPDF 不同屏幕尺寸 生成的pdf不一致,怎么解决
  • Ansible 中的文件包含与导入机制
  • java17学习笔记-Deprecate the Applet API for Removal
  • C语言基础:(十八)C语言内存函数
  • 连接远程服务器上的 jupyter notebook,解放本地电脑
  • 计算机毕设推荐:痴呆症预测可视化系统Hadoop+Spark+Vue技术栈详解
  • 生成式AI的能力边界与职业重构:从“百科实习生“到人机协作增强器
  • 人工智能学派简介
  • 当宠物机器人装上「第六感」:Deepoc 具身智能如何重构宠物机器人照看逻辑