springboot上传文件到本地,并且返回一个http访问路径

直接上代码,controller层代码:

@RestController
@RequestMapping("/common")
public class CommonController {private static final Logger log = LoggerFactory.getLogger(CommonController.class);@Resourceprivate ServerConfig serverConfig;private static final String FILE_DELIMETER = ",";/*** 通用上传请求(单个)*/@ApiOperation(value= "通用本地上传请求(单个)")@PostMapping("/upload")@ResponseBodypublic CommonResponse uploadFile(@RequestPart(name = "file") MultipartFile file) {try {// 上传文件路径String filePath = serverConfig.getProjectPath();// 上传并返回新文件名称String fileName = FileUploadUtils.upload(filePath, file);String url = serverConfig.getUrl() + fileName;JSONObject object = JSONUtil.createObj();object.putOpt("url", url);object.putOpt("fileName", fileName);object.putOpt("newFileName", FileUtils.getName(fileName));object.putOpt("originalFilename", file.getOriginalFilename());return CommonResponse.ok(object);} catch (Exception e) {return CommonResponse.fail(e.getMessage());}}/*** 通用上传请求(多个)*/@ApiOperation(value= "通用本地上传请求(多个)")@PostMapping("/uploads")@ResponseBodypublic CommonResponse uploadFiles(@RequestPart(name = "files") List<MultipartFile> files) {try {// 上传文件路径String filePath = serverConfig.getProjectPath();List<String> urls = new ArrayList<String>();List<String> fileNames = new ArrayList<String>();List<String> newFileNames = new ArrayList<String>();List<String> originalFilenames = new ArrayList<String>();for (MultipartFile file : files) {// 上传并返回新文件名称String fileName = FileUploadUtils.upload(filePath, file);String url = serverConfig.getUrl() + fileName;urls.add(url);fileNames.add(fileName);newFileNames.add(FileUtils.getName(fileName));originalFilenames.add(file.getOriginalFilename());}JSONObject object = JSONUtil.createObj();object.putOpt("urls", StringUtils.join(urls, FILE_DELIMETER));object.putOpt("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));object.putOpt("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));object.putOpt("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));return CommonResponse.ok(object);} catch (Exception e) {return CommonResponse.fail(e.getMessage());}}}

然后配置和工具类:


import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;/*** 服务相关配置**/
@Component
public class ServerConfig {/*** 获取完整的请求路径,包括:域名,端口,上下文访问路径** @return 服务地址*/public String getUrl() {HttpServletRequest request = ServletUtils.getRequest();return getDomain(request);}public static String getDomain(HttpServletRequest request) {StringBuffer url = request.getRequestURL();String contextPath = request.getServletContext().getContextPath();return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();}/*** 获取项目根路径** @return 路径地址*/public String getProjectPath() {try {Resource resource = new ClassPathResource("");String path = resource.getFile().getAbsolutePath();path = path.substring(0, path.indexOf("target") - 1);return path + Constants.RESOURCE_PREFIX;} catch (Exception e) {String path = Constants.RESOURCE_PREFIX;if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {path = "D:" + Constants.RESOURCE_PREFIX;}return path;}}}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;/*** <p>*     WebMvc配置类* </p>***/
@Import({GlobalExceptionHandler.class})
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Resourceprivate ServerConfig serverConfig;@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController(BaseConstant.WEBSOCKET_HTML).setViewName(BaseConstant.WEBSOCKET);registry.addViewController(BaseConstant.MAIL_HTML).setViewName(BaseConstant.MAIL);}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(BaseConstant.DOC_HTML).addResourceLocations(BaseConstant.META_INF_RESOURCES);registry.addResourceHandler(BaseConstant.WEBJARS).addResourceLocations(BaseConstant.META_INF_RESOURCES_WEBJARS);String filePath = "file:"+serverConfig.getProjectPath();if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {registry.addResourceHandler("/upload/**").addResourceLocations(filePath);}else {registry.addResourceHandler("/upload/**").addResourceLocations(filePath);}}@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// 添加参数解析器argumentResolvers.add(new SingleRequestBodyResolver());}/*** @param registry* @author quzhaodong* @date 2020/11/3**/@Overridepublic void addInterceptors(InterceptorRegistry registry) {}/*** 允许跨域请求*/@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration(BaseConstant.STAR_STAR, corsConfig());return new CorsFilter(source);}/*** <p>*     Jackson全局转化long类型为String,解决jackson序列化时long类型缺失精度问题* </p>*/@Beanpublic Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {Jackson2ObjectMapperBuilderCustomizer customizer = jacksonObjectMapperBuilder -> {jacksonObjectMapperBuilder.serializerByType(BigInteger.class, ToStringSerializer.instance);
//            jacksonObjectMapperBuilder.serializerByType(long.class, ToStringSerializer.instance);jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance);
//            jacksonObjectMapperBuilder.serializerByType(Long.TYPE, ToStringSerializer.instance);//空值 null 进行序列化jacksonObjectMapperBuilder.featuresToEnable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);jacksonObjectMapperBuilder.serializationInclusion(JsonInclude.Include.ALWAYS);// 指定日期格式// 序列化jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));// 反序列化jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));};return customizer;}/***     跨域配置*/private CorsConfiguration corsConfig() {CorsConfiguration corsConfiguration = new CorsConfiguration();// 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)corsConfiguration.addAllowedOriginPattern(BaseConstant.STAR);corsConfiguration.addAllowedHeader(BaseConstant.STAR);corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);corsConfiguration.addAllowedMethod(HttpMethod.GET);corsConfiguration.addAllowedMethod(HttpMethod.POST);corsConfiguration.addAllowedMethod(HttpMethod.PATCH);corsConfiguration.addAllowedMethod(HttpMethod.PUT);corsConfiguration.addAllowedMethod(HttpMethod.DELETE);corsConfiguration.setAllowCredentials(true);corsConfiguration.setMaxAge(3600L);return corsConfiguration;}@Beanpublic ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {return new ByteArrayHttpMessageConverter();}/*@Beanpublic CustomizationBean getCustomizationBean() {return new CustomizationBean();}*/}

上传工具类:

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;/*** 文件上传工具类** @author ruoyi*/
public class FileUploadUtils {/*** 根据文件路径上传** @param baseDir 相对应用的基目录* @param file    上传的文件* @return 文件名称* @throws IOException*/public static final String upload(String baseDir, MultipartFile file) throws IOException {try {return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);} catch (Exception e) {throw new IOException(e.getMessage(), e);}}/*** 文件上传** @param baseDir          相对应用的基目录* @param file             上传的文件* @param allowedExtension 上传文件类型* @return 返回上传成功的文件名* @throws IOException 比如读写文件出错时*/public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws IOException {String fileName = extractFilename(file);assertAllowed(file, allowedExtension);String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));return getPathFileName(fileName);}/*** 编码文件名*/public static final String extractFilename(MultipartFile file) {return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),FilenameUtils.getBaseName(file.getOriginalFilename()), SnowFlakeManager.getSnowFlake().nextId(), getExtension(file));}public static final File getAbsoluteFile(String uploadDir, String fileName) {File desc = new File(uploadDir + File.separator + fileName);if (!desc.exists()) {if (!desc.getParentFile().exists()) {desc.getParentFile().mkdirs();}}return desc;}public static final String getPathFileName(String fileName) {return Constants.RESOURCE_PREFIX + fileName;
//        int dirLastIndex = getDefaultBaseDir().length() + 1;
//        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
//        if (StringUtils.isNotBlank(currentDir)) {
//            return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
//        }
//        return Constants.RESOURCE_PREFIX + "/" + fileName;}/*** 文件校验** @param file 上传的文件* @return* @throws ServiceException*/public static final void assertAllowed(MultipartFile file, String[] allowedExtension)throws IOException {long size = file.getSize();String fileName = file.getOriginalFilename();String extension = getExtension(file);if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {throw new IOException("不支持文件:" + fileName + "的文件类型!");}}/*** 判断MIME类型是否是允许的MIME类型** @param extension* @param allowedExtension* @return*/public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {for (String str : allowedExtension) {if (str.equalsIgnoreCase(extension)) {return true;}}return false;}/*** 获取文件名的后缀** @param file 表单文件* @return 后缀名*/public static final String getExtension(MultipartFile file) {String extension = FilenameUtils.getExtension(file.getOriginalFilename());if (StringUtils.isEmpty(extension)) {extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));}return extension;}

常量类 

/*** 通用常量信息**/
public class Constants
{/*** 资源映射路径 前缀*/public static final String RESOURCE_PREFIX = "/upload/";}

接下来讲一下思路:

1、首先我们是要把文件上传到项目的目录中,获取项目路径的方法是这个:

    /*** 获取项目根路径** @return 路径地址*/public String getProjectPath() {try {Resource resource = new ClassPathResource("");String path = resource.getFile().getAbsolutePath();path = path.substring(0, path.indexOf("target") - 1);return path + Constants.RESOURCE_PREFIX;} catch (Exception e) {String path = Constants.RESOURCE_PREFIX;if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {path = "D:" + Constants.RESOURCE_PREFIX;}return path;}}

假如我们项目的路径是:D:/project/crm/admin,我们这里返回的路径就是D:/project/crm/admin/upload

2、文件上传,用到的方法是这个:

    /*** 文件上传** @param baseDir          相对应用的基目录* @param file             上传的文件* @param allowedExtension 上传文件类型* @return 返回上传成功的文件名* @throws IOException 比如读写文件出错时*/public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws IOException {String fileName = extractFilename(file);assertAllowed(file, allowedExtension);String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();file.transferTo(Paths.get(absPath));return getPathFileName(fileName);}

上传方法就是 file.transferTo(Paths.get(absPath));

3、然后就是返回一个可以访问的路径,方法是:

//这里只返回图片的地址,不带项目的url,String url = serverConfig.getUrl() + fileName;public static final String getPathFileName(String fileName) {return Constants.RESOURCE_PREFIX + fileName;}

4。经过拼接之后,我们会发现,图片上传的位置是:

D:/project/crm/admin/upload/2025/05/05/1.jpg

返回的url是:http://127.0.0.1:8080/upload/2025/05/05/1.jpg

这样就可以访问了。为什么可以访问呢,是因为我们配置了静态资源的映射,具体配置为:

    @Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(BaseConstant.DOC_HTML).addResourceLocations(BaseConstant.META_INF_RESOURCES);registry.addResourceHandler(BaseConstant.WEBJARS).addResourceLocations(BaseConstant.META_INF_RESOURCES_WEBJARS);String filePath = "file:"+serverConfig.getProjectPath();if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {registry.addResourceHandler("/upload/**").addResourceLocations(filePath);}else {registry.addResourceHandler("/upload/**").addResourceLocations(filePath);}}

这就是将文件上传到本地,并且返回一个url,可以正常访问图片。

如果你要匿名访问,需要在token的配置文件中设置/upload/**不需要token

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/2015.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++模拟实现vector

目录 1.代码实现 2.注意事项 1.成员变量 2. 不能使用memcpy函数拷贝数据 1.用string类型测试时&#xff0c;要考虑到vs可能把数据存储在数组buffer里面 3.insert函数中指针的失效性 1.加引用&#xff0c;那么就不能传常量&#xff0c;比如v.begin() 3 2.加引用&#x…

【ArcGIS Pro微课1000例】0028:绘制酒店分布热力图(POI数据)

本文讲解在ArcGIS Pro中文版中,基于长沙市酒店宾馆分布矢量点数据(POI数据)绘制酒店分布热力图。 文章目录 一、加载酒店分布数据二、绘制热度图参考阅读: 【GeoDa实用技巧100例】004:绘制长沙市宾馆热度图 【ArcGIS微课1000例】0070:制作宾馆酒店分布热度热力图 一、加载…

【机器学习】基于卷积神经网络 CNN 的猫狗分类问题

文章目录 一、卷积神经网络的介绍1.1 什么是卷积神经网络1.2 重要层的说明1.3 应用领域二、 软件、环境配置2.1 安装Anaconda2.2 环境准备 三、猫狗分类示例3.1 图像数据预处理3.2 基准模型3.3 数据增强3.4 dropout层四、总结 一、卷积神经网络的介绍 1.1 什么是卷积神经网络 …

el-table找出当前单元格与对应的上下列的值

当前单元格与对应的上下列的值如果不相同就设置个红色边框 当前单元格与对应的上下列的值如果不相同就设置个红色边框 当前单元格与对应的上下列的值如果不相同就设置个红色边框 以下是示例代码&#xff0c;对tableData数据的name字段进行处理 如果当前name值与上一条数据的na…

《Programming Abstractions In C》阅读笔记p69-p71

今日完成《Programming Abstractions In C》阅读P69-p71。 一、技术总结 涉及到的技术知识点有“symbolic constant”,”Array declaration”&#xff0c;“Array selection”。 #include <stdio.h> #define NJudges 5int main(int argc, char const *argv[]) {// Arra…

mybatis作用域和生命周期解读

目录 SqlSessionFactoryBuilder SqlSessionFactory SqlSession 依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器&#xff0c;并将它们直接注入到你的 bean 中&#xff0c;因此可以直接忽略它们的生命周期。 SqlSessionFactoryBuilder 这个类可以被实例化…

Scala集合 - List

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 一、不可变List 1. 创建List 2. 取指定的数据 3. 向List中添加元素 4. 遍历List 5. 集合间合并 - 扁平化处理 二、可变List 1. 创建可变集合对象 2. 添加元素 3. 修改元素 4. 删除元素 一、…

kafka生产端是TCP连接管理

目录 前言&#xff1a; Kafka生产者程序 Kafka生产者客户端如何创建TCP连接 Kafka生产者客户端如何关闭TCP连接 总结&#xff1a; 参考资料 前言&#xff1a; 在网络层协议中&#xff0c;TCP作用在第四层传输层、Http协议作用在第七层最上层应用层&#xff0c;一个完整的…

写给小白的ChatGPT和AI原理

前言 随着ChatGPT等生成式AI的大火&#xff0c;很多开发者都对AI感兴趣。笔者是一名应用层的开发工程师&#xff0c;想必很多类似的开发者都对AI这块不太了解&#xff0c;故而从自己的理解&#xff0c;写一篇給小白的AI入门文章&#xff0c;希望可以帮助到大家。 这是GPT对本…

HMLT学习笔记

1. HTML说明 1.1 文档声明 用于告诉浏览器文档版本。1.引入样式&#xff0c;2.自身样式&#xff0c;3.使用框架&#xff08;html与xhtml同样&#xff09; <!-- 引入CSS的文档 --><!-- HTML文档 --><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN&qu…

EfficientNet论文笔记

EfficientNet论文笔记 通过NAS平衡了channel&#xff0c;depth&#xff0c;resolution&#xff0c;发现在相同的FLOPs下&#xff0c;同时增加 depth和 resolution的效果最好。 数据集效果小于resolution怎么办&#xff1f; EfficientNet—b0框架 表格中每个MBConv后会跟一个…

科技资讯|Apple Vision Pro新专利,关于相对惯性测量系统的校正

美国专利商标局正式授予苹果一项 Apple Vision Pro 相关专利&#xff0c;该专利涵盖了具有视觉校正功能的相对惯性测量系统。这样的系统用于弥补头显内的眼前庭不匹配&#xff0c;当 VR 头显中发生的事情与现实世界环境中发生的运动不匹配时&#xff0c;可能会导致恶心。 苹果…

11. 利用Tomcat服务器配置HTTPS双向认定

文章目录 Tomcat配置HTTPS1.为服务器生成证书2.为客户端生成证书3.让服务器信任客户端证书4.将该文件导入到服务器的证书库&#xff0c;添加为一个信任证书使用命令如下&#xff1a;5.查看证书库6.让客户端信任服务器证书7.配置tomcat8.验证 Tomcat配置HTTPS 1.启动cmd控制台&…

DirectX12(D3D12)基础教程(二十二) ——HDR IBL 等距柱面环境光源加载和解算及 GS 一次性渲染到 CubeMap

前序文章目录 DirectX12&#xff08;D3D12&#xff09;基础教程&#xff08;一&#xff09;——基础教程 DirectX12&#xff08;D3D12&#xff09;基础教程&#xff08;二&#xff09;——理解根签名、初识显存管理和加载纹理、理解资源屏障 DirectX12&#xff08;D3D12&…

【Linux】进程信号之信号的产生

进程信号 一 一、信号入门1、信号的一些特性2、信号的处理方式信号捕捉初识 3、Linux下的信号 二、信号的产生1、通过终端按键产生信号2、调用系统函数向进程发信号a、kill函数b、raise函数c、abort函数 3. 由软件条件产生信号4、硬件异常产生信号 结语 一、信号入门 什么是信号…

怎么解决亚马逊跟卖?为何卖家总是举报不成功?

以前大家都是从跟卖的时代走向现在的品牌化运营之路&#xff0c;但是现在跟卖已经从大家都模仿的对象变成了大部分卖家厌恶的对象&#xff0c;那么怎么解决这个跟卖问题呢&#xff1f;目前最直接的方法就是进入亚马逊后台进行举报&#xff0c;但是大概率是失败的。 一、举报违…

MySQL操作库

MySQL操作库 一.创建数据库1. 创建数据库的方式2. 创建数据库时的编码问题3. 指定编码创建数据库4. 验证校验规则对数据库的影响 二.数据库与文件系统的关系三.操纵数据库1. 查看数据库2. 删除数据库3. 修改数据库 四.数据库的备份和恢复1.数据库的备份2.数据库的恢复 五.查看连…

C++基础算法排序篇

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C算法 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要讲解C算法中所涉及到的两个排序算法&#xff0c;快排和归并。 文章…

【JavaEE】HTTP请求的构造

目录 1、通过form表单构造HTTP请求 2、通过JS的ajax构造HTTP请求 3、Postman的安装和简单使用 常见的构造HTTP请求的方式有一下几种&#xff1a; 直接通过浏览器的地址栏&#xff0c;输入一个URL&#xff0c;就可以构造一个GET请求HTML中的一些特殊标签&#xff0c;也会触发…

IT技术岗的面试技巧分享

我们在找工作时,需要结合自己的现状,针对意向企业做好充分准备。作为程序员,你有哪些面试IT技术岗的技巧?你可以从一下几个方向谈谈你的想法和观点。 方向一:分享你面试IT公司的小技巧 1、事先和邀约人了解公司的基本情况,比如公司的行业,规模,研发人员占比等 2、事先和…