当前位置:   article > 正文

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

springboot文件上传返回url

直接上代码,controller层代码:

  1. @RestController
  2. @RequestMapping("/common")
  3. public class CommonController {
  4. private static final Logger log = LoggerFactory.getLogger(CommonController.class);
  5. @Resource
  6. private ServerConfig serverConfig;
  7. private static final String FILE_DELIMETER = ",";
  8. /**
  9. * 通用上传请求(单个)
  10. */
  11. @ApiOperation(value= "通用本地上传请求(单个)")
  12. @PostMapping("/upload")
  13. @ResponseBody
  14. public CommonResponse uploadFile(@RequestPart(name = "file") MultipartFile file) {
  15. try {
  16. // 上传文件路径
  17. String filePath = serverConfig.getProjectPath();
  18. // 上传并返回新文件名称
  19. String fileName = FileUploadUtils.upload(filePath, file);
  20. String url = serverConfig.getUrl() + fileName;
  21. JSONObject object = JSONUtil.createObj();
  22. object.putOpt("url", url);
  23. object.putOpt("fileName", fileName);
  24. object.putOpt("newFileName", FileUtils.getName(fileName));
  25. object.putOpt("originalFilename", file.getOriginalFilename());
  26. return CommonResponse.ok(object);
  27. } catch (Exception e) {
  28. return CommonResponse.fail(e.getMessage());
  29. }
  30. }
  31. /**
  32. * 通用上传请求(多个)
  33. */
  34. @ApiOperation(value= "通用本地上传请求(多个)")
  35. @PostMapping("/uploads")
  36. @ResponseBody
  37. public CommonResponse uploadFiles(@RequestPart(name = "files") List<MultipartFile> files) {
  38. try {
  39. // 上传文件路径
  40. String filePath = serverConfig.getProjectPath();
  41. List<String> urls = new ArrayList<String>();
  42. List<String> fileNames = new ArrayList<String>();
  43. List<String> newFileNames = new ArrayList<String>();
  44. List<String> originalFilenames = new ArrayList<String>();
  45. for (MultipartFile file : files) {
  46. // 上传并返回新文件名称
  47. String fileName = FileUploadUtils.upload(filePath, file);
  48. String url = serverConfig.getUrl() + fileName;
  49. urls.add(url);
  50. fileNames.add(fileName);
  51. newFileNames.add(FileUtils.getName(fileName));
  52. originalFilenames.add(file.getOriginalFilename());
  53. }
  54. JSONObject object = JSONUtil.createObj();
  55. object.putOpt("urls", StringUtils.join(urls, FILE_DELIMETER));
  56. object.putOpt("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
  57. object.putOpt("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
  58. object.putOpt("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
  59. return CommonResponse.ok(object);
  60. } catch (Exception e) {
  61. return CommonResponse.fail(e.getMessage());
  62. }
  63. }
  64. }

然后配置和工具类:

  1. import org.springframework.core.io.ClassPathResource;
  2. import org.springframework.core.io.Resource;
  3. import org.springframework.stereotype.Component;
  4. import javax.servlet.http.HttpServletRequest;
  5. /**
  6. * 服务相关配置
  7. *
  8. */
  9. @Component
  10. public class ServerConfig {
  11. /**
  12. * 获取完整的请求路径,包括:域名,端口,上下文访问路径
  13. *
  14. * @return 服务地址
  15. */
  16. public String getUrl() {
  17. HttpServletRequest request = ServletUtils.getRequest();
  18. return getDomain(request);
  19. }
  20. public static String getDomain(HttpServletRequest request) {
  21. StringBuffer url = request.getRequestURL();
  22. String contextPath = request.getServletContext().getContextPath();
  23. return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
  24. }
  25. /**
  26. * 获取项目根路径
  27. *
  28. * @return 路径地址
  29. */
  30. public String getProjectPath() {
  31. try {
  32. Resource resource = new ClassPathResource("");
  33. String path = resource.getFile().getAbsolutePath();
  34. path = path.substring(0, path.indexOf("target") - 1);
  35. return path + Constants.RESOURCE_PREFIX;
  36. } catch (Exception e) {
  37. String path = Constants.RESOURCE_PREFIX;
  38. if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
  39. path = "D:" + Constants.RESOURCE_PREFIX;
  40. }
  41. return path;
  42. }
  43. }
  44. }
  1. import com.fasterxml.jackson.annotation.JsonInclude;
  2. import com.fasterxml.jackson.databind.DeserializationFeature;
  3. import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
  4. import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
  5. import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
  6. import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.context.annotation.Import;
  10. import org.springframework.http.HttpMethod;
  11. import org.springframework.http.converter.ByteArrayHttpMessageConverter;
  12. import org.springframework.web.cors.CorsConfiguration;
  13. import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  14. import org.springframework.web.filter.CorsFilter;
  15. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  16. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  17. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  18. import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
  19. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  20. import javax.annotation.Resource;
  21. import java.math.BigInteger;
  22. import java.time.LocalDateTime;
  23. import java.time.format.DateTimeFormatter;
  24. import java.util.List;
  25. /**
  26. * <p>
  27. * WebMvc配置类
  28. * </p>
  29. *
  30. **/
  31. @Import({GlobalExceptionHandler.class})
  32. @Configuration
  33. public class WebMvcConfig implements WebMvcConfigurer {
  34. @Resource
  35. private ServerConfig serverConfig;
  36. @Override
  37. public void addViewControllers(ViewControllerRegistry registry) {
  38. registry.addViewController(BaseConstant.WEBSOCKET_HTML).setViewName(BaseConstant.WEBSOCKET);
  39. registry.addViewController(BaseConstant.MAIL_HTML).setViewName(BaseConstant.MAIL);
  40. }
  41. @Override
  42. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  43. registry.addResourceHandler(BaseConstant.DOC_HTML)
  44. .addResourceLocations(BaseConstant.META_INF_RESOURCES);
  45. registry.addResourceHandler(BaseConstant.WEBJARS)
  46. .addResourceLocations(BaseConstant.META_INF_RESOURCES_WEBJARS);
  47. String filePath = "file:"+serverConfig.getProjectPath();
  48. if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
  49. registry.addResourceHandler("/upload/**").addResourceLocations(filePath);
  50. }else {
  51. registry.addResourceHandler("/upload/**").addResourceLocations(filePath);
  52. }
  53. }
  54. @Override
  55. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  56. // 添加参数解析器
  57. argumentResolvers.add(new SingleRequestBodyResolver());
  58. }
  59. /**
  60. * @param registry
  61. * @author quzhaodong
  62. * @date 2020/11/3
  63. **/
  64. @Override
  65. public void addInterceptors(InterceptorRegistry registry) {
  66. }
  67. /**
  68. * 允许跨域请求
  69. */
  70. @Bean
  71. public CorsFilter corsFilter() {
  72. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  73. source.registerCorsConfiguration(BaseConstant.STAR_STAR, corsConfig());
  74. return new CorsFilter(source);
  75. }
  76. /**
  77. * <p>
  78. * Jackson全局转化long类型为String,解决jackson序列化时long类型缺失精度问题
  79. * </p>
  80. */
  81. @Bean
  82. public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
  83. Jackson2ObjectMapperBuilderCustomizer customizer = jacksonObjectMapperBuilder -> {
  84. jacksonObjectMapperBuilder.serializerByType(BigInteger.class, ToStringSerializer.instance);
  85. // jacksonObjectMapperBuilder.serializerByType(long.class, ToStringSerializer.instance);
  86. jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance);
  87. // jacksonObjectMapperBuilder.serializerByType(Long.TYPE, ToStringSerializer.instance);
  88. //空值 null 进行序列化
  89. jacksonObjectMapperBuilder.featuresToEnable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
  90. jacksonObjectMapperBuilder.serializationInclusion(JsonInclude.Include.ALWAYS);
  91. // 指定日期格式
  92. // 序列化
  93. jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
  94. // 反序列化
  95. jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
  96. };
  97. return customizer;
  98. }
  99. /**
  100. * 跨域配置
  101. */
  102. private CorsConfiguration corsConfig() {
  103. CorsConfiguration corsConfiguration = new CorsConfiguration();
  104. // 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)
  105. corsConfiguration.addAllowedOriginPattern(BaseConstant.STAR);
  106. corsConfiguration.addAllowedHeader(BaseConstant.STAR);
  107. corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
  108. corsConfiguration.addAllowedMethod(HttpMethod.GET);
  109. corsConfiguration.addAllowedMethod(HttpMethod.POST);
  110. corsConfiguration.addAllowedMethod(HttpMethod.PATCH);
  111. corsConfiguration.addAllowedMethod(HttpMethod.PUT);
  112. corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
  113. corsConfiguration.setAllowCredentials(true);
  114. corsConfiguration.setMaxAge(3600L);
  115. return corsConfiguration;
  116. }
  117. @Bean
  118. public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
  119. return new ByteArrayHttpMessageConverter();
  120. }
  121. /*@Bean
  122. public CustomizationBean getCustomizationBean() {
  123. return new CustomizationBean();
  124. }*/
  125. }

上传工具类:

  1. import java.io.File;
  2. import java.io.IOException;
  3. import java.nio.file.Paths;
  4. import java.util.Objects;
  5. import org.apache.commons.io.FilenameUtils;
  6. import org.springframework.web.multipart.MultipartFile;
  7. /**
  8. * 文件上传工具类
  9. *
  10. * @author ruoyi
  11. */
  12. public class FileUploadUtils {
  13. /**
  14. * 根据文件路径上传
  15. *
  16. * @param baseDir 相对应用的基目录
  17. * @param file 上传的文件
  18. * @return 文件名称
  19. * @throws IOException
  20. */
  21. public static final String upload(String baseDir, MultipartFile file) throws IOException {
  22. try {
  23. return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
  24. } catch (Exception e) {
  25. throw new IOException(e.getMessage(), e);
  26. }
  27. }
  28. /**
  29. * 文件上传
  30. *
  31. * @param baseDir 相对应用的基目录
  32. * @param file 上传的文件
  33. * @param allowedExtension 上传文件类型
  34. * @return 返回上传成功的文件名
  35. * @throws IOException 比如读写文件出错时
  36. */
  37. public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws IOException {
  38. String fileName = extractFilename(file);
  39. assertAllowed(file, allowedExtension);
  40. String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
  41. file.transferTo(Paths.get(absPath));
  42. return getPathFileName(fileName);
  43. }
  44. /**
  45. * 编码文件名
  46. */
  47. public static final String extractFilename(MultipartFile file) {
  48. return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
  49. FilenameUtils.getBaseName(file.getOriginalFilename()), SnowFlakeManager.getSnowFlake().nextId(), getExtension(file));
  50. }
  51. public static final File getAbsoluteFile(String uploadDir, String fileName) {
  52. File desc = new File(uploadDir + File.separator + fileName);
  53. if (!desc.exists()) {
  54. if (!desc.getParentFile().exists()) {
  55. desc.getParentFile().mkdirs();
  56. }
  57. }
  58. return desc;
  59. }
  60. public static final String getPathFileName(String fileName) {
  61. return Constants.RESOURCE_PREFIX + fileName;
  62. // int dirLastIndex = getDefaultBaseDir().length() + 1;
  63. // String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
  64. // if (StringUtils.isNotBlank(currentDir)) {
  65. // return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
  66. // }
  67. // return Constants.RESOURCE_PREFIX + "/" + fileName;
  68. }
  69. /**
  70. * 文件校验
  71. *
  72. * @param file 上传的文件
  73. * @return
  74. * @throws ServiceException
  75. */
  76. public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
  77. throws IOException {
  78. long size = file.getSize();
  79. String fileName = file.getOriginalFilename();
  80. String extension = getExtension(file);
  81. if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
  82. throw new IOException("不支持文件:" + fileName + "的文件类型!");
  83. }
  84. }
  85. /**
  86. * 判断MIME类型是否是允许的MIME类型
  87. *
  88. * @param extension
  89. * @param allowedExtension
  90. * @return
  91. */
  92. public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
  93. for (String str : allowedExtension) {
  94. if (str.equalsIgnoreCase(extension)) {
  95. return true;
  96. }
  97. }
  98. return false;
  99. }
  100. /**
  101. * 获取文件名的后缀
  102. *
  103. * @param file 表单文件
  104. * @return 后缀名
  105. */
  106. public static final String getExtension(MultipartFile file) {
  107. String extension = FilenameUtils.getExtension(file.getOriginalFilename());
  108. if (StringUtils.isEmpty(extension)) {
  109. extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
  110. }
  111. return extension;
  112. }

常量类 

  1. /**
  2. * 通用常量信息
  3. *
  4. */
  5. public class Constants
  6. {
  7. /**
  8. * 资源映射路径 前缀
  9. */
  10. public static final String RESOURCE_PREFIX = "/upload/";
  11. }

接下来讲一下思路:

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

  1. /**
  2. * 获取项目根路径
  3. *
  4. * @return 路径地址
  5. */
  6. public String getProjectPath() {
  7. try {
  8. Resource resource = new ClassPathResource("");
  9. String path = resource.getFile().getAbsolutePath();
  10. path = path.substring(0, path.indexOf("target") - 1);
  11. return path + Constants.RESOURCE_PREFIX;
  12. } catch (Exception e) {
  13. String path = Constants.RESOURCE_PREFIX;
  14. if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
  15. path = "D:" + Constants.RESOURCE_PREFIX;
  16. }
  17. return path;
  18. }
  19. }

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

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

  1. /**
  2. * 文件上传
  3. *
  4. * @param baseDir 相对应用的基目录
  5. * @param file 上传的文件
  6. * @param allowedExtension 上传文件类型
  7. * @return 返回上传成功的文件名
  8. * @throws IOException 比如读写文件出错时
  9. */
  10. public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws IOException {
  11. String fileName = extractFilename(file);
  12. assertAllowed(file, allowedExtension);
  13. String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
  14. file.transferTo(Paths.get(absPath));
  15. return getPathFileName(fileName);
  16. }

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

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

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

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

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

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

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

  1. @Override
  2. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  3. registry.addResourceHandler(BaseConstant.DOC_HTML)
  4. .addResourceLocations(BaseConstant.META_INF_RESOURCES);
  5. registry.addResourceHandler(BaseConstant.WEBJARS)
  6. .addResourceLocations(BaseConstant.META_INF_RESOURCES_WEBJARS);
  7. String filePath = "file:"+serverConfig.getProjectPath();
  8. if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") >= 0) {
  9. registry.addResourceHandler("/upload/**").addResourceLocations(filePath);
  10. }else {
  11. registry.addResourceHandler("/upload/**").addResourceLocations(filePath);
  12. }
  13. }

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/815910
推荐阅读
相关标签
  

闽ICP备14008679号