解决SpringBoot上传图片无法显示问题,开发,部署都能过,windows,linux都能过
application.properties
# 是否支持多部分上传。
spring.servlet.multipart.enabled=true
# 最大支持文件上传的大小
spring.servlet.multipart.max-file-size=10MB
# 支持请求最大文件上传的大小
spring.servlet.multipart.max-request-size=10MB
#上传图片的静态资源路径
UPLOAD_STATIC_PATH=/Upload/**
#上传图片的URL访问路径
UPLOAD_ACCESS_PATH=/Upload
# 上传图片存放的物理路径,注意必须是/路径分隔符,最后面也要带上的路径分隔符,windows也一样
UPLOAD_PHYSICAL_PATH=E://Demo/JAVA/Upload/
WebMvcConfigurerImpl.java
@Configuration public class WebMvcConfigurerImpl implements WebMvcConfigurer { // region 上传文件设置 /** * 上传图片存放的物理路径 */ @Value("${UPLOAD_PHYSICAL_PATH}") private String UPLOAD_PHYSICAL_PATH; /** * 上传图片的静态资源路径 */ @Value("${UPLOAD_STATIC_PATH}") private String UPLOAD_STATIC_PATH; /** * springboot jar包运行文件上传及显示 * https://www.jianshu.com/p/5e1a4e4ab994 * https://www.jianshu.com/p/96b9d2118259 * springboot设置资源文件的访问路径,并判断Windows服务器还是linux服务器 * https://blog.csdn.net/qq_41274509/article/details/101700838 * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { String staticMapping=UPLOAD_STATIC_PATH; String localDirectory = "file:" + UPLOAD_PHYSICAL_PATH; String os = System.getProperty("os.name"); if (os.toLowerCase().startsWith("win")) { //如果是Windows系统 //其中localDirectory变量是外部文件夹,文件需要上传到该文件夹中去,staticMapping就是映射的静态资源请求路径了 registry.addResourceHandler(staticMapping) .addResourceLocations(localDirectory);//媒体资源绝对路径 } else { //linux 和mac registry.addResourceHandler(staticMapping) .addResourceLocations(localDirectory);//媒体资源绝对路径 } WebMvcConfigurer.super.addResourceHandlers(registry); } /** * 限制文件上传的大小启动类(配置文件里出) * @return */ // @Bean // public MultipartConfigElement multipartConfigElement(){ // MultipartConfigFactory factory = new MultipartConfigFactory(); // factory.setMaxFileSize(DataSize.ofMegabytes(10)); // factory.setMaxRequestSize(DataSize.ofMegabytes(10)); // return factory.createMultipartConfig(); // } // endregion }
WebSecurityConfigurerAdapterExtend.java(如果使用SrpingSecurity的话也需要设置权限通过)
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfigurerAdapterExtend extends WebSecurityConfigurerAdapter { …… /** * 上传图片的静态资源路径 */ @Value("${UPLOAD_STATIC_PATH}") private String UPLOAD_STATIC_PATH; @Override public void configure(WebSecurity web) throws Exception { // 设置拦截忽略文件夹,可以对静态资源放行 web.ignoring().antMatchers(UPLOAD_STATIC_PATH); } }
UploadController.java(上传控制器)
package tb.view.sbmsm.easyuidemo.controller; import com.alibaba.druid.util.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import tb.helper.DateHelper; import tb.helper.IOHelper; import tb.model.JsonManager; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; /** * <pre> * 接收上传文件数据的控制器 * </pre> * * @author wangyunpeng * @date 2020/3/1 11:09 */ @Controller @RequestMapping("/Upload") public class UploadController { private Map<String, String[]> _dict = new HashMap<String, String[]>(); private String WEB_SITE_NAME = "test"; /** * 上传图片存放的物理路径 */ @Value("${UPLOAD_PHYSICAL_PATH}") private String UPLOAD_PHYSICAL_PATH; /** * 上传图片的URL访问路径 */ @Value("${UPLOAD_ACCESS_PATH}") private String UPLOAD_ACCESS_PATH; public UploadController() { this._dict.put(String.format("/%s/SPU/Image/", WEB_SITE_NAME), new String[]{".jpeg", ".jpg", ".gif", ".bmp", ".png"}); this._dict.put(String.format("/%s/SPU/Document/", WEB_SITE_NAME), new String[]{".doc", ".xls", ".ppt", ".docx", ".xlsx", ".pptx", ".txt", ".rtf"}); this._dict.put(String.format("/%s/SPU/Video/", WEB_SITE_NAME), new String[]{".mp3"}); this._dict.put(String.format("/%s/SPU/Audio/", WEB_SITE_NAME), new String[]{".flv"}); } @RequestMapping(value = "SingleNormal", method = RequestMethod.POST, produces = "application/json;charset=utf-8") @ResponseBody public String singleNormal(HttpServletRequest request) throws Exception { String fileScope = request.getParameter("fileScope"); if (StringUtils.isEmpty(fileScope)) { return JsonManager.getError(1, "请指定fileScope"); } // List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("fileList"); //可能会有多个文件同时上传 MultiValueMap<String, MultipartFile> multiValues = ((MultipartHttpServletRequest) request).getMultiFileMap(); if (multiValues == null || multiValues.size() < 1) { return JsonManager.getError(1, "您没有上传任何文档!"); } MultipartFile file = null; for (Map.Entry<String, List<MultipartFile>> entry : multiValues.entrySet()) { for (MultipartFile value : entry.getValue()) { file = value; break; } } if (file == null) { return JsonManager.getError(1, "您没有上传任何文档!"); } String fileExtension = IOHelper.getFileExt(file.getOriginalFilename()); String folder = String.format("/%s/SPU/File/", WEB_SITE_NAME); //未识别的文件存入File文件夹 boolean has = false; for (Map.Entry<String, String[]> dict : this._dict.entrySet()) { for (String item : dict.getValue()) { if (StringUtils.equalsIgnoreCase(item, fileExtension)) { folder = dict.getKey().replace("SPU", fileScope); } } } ImageBiz imageBiz = new ImageBiz(); folder = IOHelper.combinePathJar(folder, imageBiz.TEMP); folder = IOHelper.combinePathJar(folder, DateHelper.toString(DateHelper.now(), "yyyyMM")); String physicalDirPath = IOHelper.combinePathJar(UPLOAD_PHYSICAL_PATH, folder); IOHelper.createDirectory(physicalDirPath); String fileName = UUID.randomUUID().toString() + fileExtension; String physicalFilePath = IOHelper.combinePathJar(physicalDirPath, fileName); try (BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(physicalFilePath)))) { stream.write(file.getBytes()); } String absolutePath = IOHelper.combinePathJar(folder, fileName); String newAbsolutePath = imageBiz.moveFile(absolutePath, physicalFilePath); Map<String, String> output = new HashMap<>(); output.put("FileName", fileName); output.put("FilePath", IOHelper.combinePathJar(UPLOAD_ACCESS_PATH, newAbsolutePath)); output.put("FileExtension", fileExtension); output.put("OriginalName", file.getName()); BufferedImage image = ImageIO.read(file.getInputStream()); { output.put("Width", image.getWidth() + ""); output.put("Height", image.getHeight() + ""); } return JsonManager.getSuccess(output, "成功!"); } public class ImageBiz { /// <summary> /// 上传图片临时文件夹名称 /// </summary> public final String TEMP = "$~Temp/"; /// <summary> /// 将临时目录中的文件移动到真实路径 /// </summary> /// <param name="absolutePath">包含/$~Temp/的绝对路径</param> /// <param name="filePhysicalPath">包含/$~Temp/的物理路径</param> /// <returns>返回修改后的绝对路径</returns> public String moveFile(String absolutePath, String filePhysicalPath) throws IOException { if (absolutePath != null && !absolutePath.startsWith("http://") && absolutePath.contains(TEMP)) { String directorySeparator = IOHelper.DirectorySeparatorCharJar; String newFilePhysicalPath = filePhysicalPath.replace(directorySeparator + TEMP.substring(0, TEMP.length() - 1) + directorySeparator, directorySeparator); IOHelper.deleteFile(newFilePhysicalPath); //复制图片 IOHelper.copyFile(filePhysicalPath, newFilePhysicalPath); absolutePath = absolutePath.replace(directorySeparator + TEMP, directorySeparator);//url path IOHelper.deleteFile(filePhysicalPath); } return absolutePath; } } }
IOHelper.java(文件路径,磁盘操作)
/** * 得到文件的扩展名(开头包含“.”) * * @param fileName * @return */ public static String getFileExt(String fileName) { if ((fileName != null) && (fileName.length() > 0)) { int dotIndex = fileName.lastIndexOf('.'); if ((dotIndex > -1) && (dotIndex < (fileName.length() - 1))) { return fileName.substring(dotIndex); } } return fileName; } /** * 目录分隔符 / (仅是jar包的目录分割符) http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html * <p> * IDE 可以使用File.separator , jar包里面File.separator就不行了,只能改成“/”。 */ public static final String DirectorySeparatorCharJar = "/"; /** * 将多个字符串合并成一个目录字符串(仅仅是Jar包里面的目录使用此方法) * * @param paths 每一个字符串的末尾不能是目录分隔符 \ or / * @return */ public static String combinePathJar(String... paths) { String path = null; int length = paths.length; List<String> pathList = new ArrayList<>(length); for (int i = 0; i < length; i++) { path = paths[i]; int lastIndex = path.lastIndexOf(DirectorySeparatorCharJar); if (lastIndex == path.length() - 1) { path = path.substring(0, lastIndex); } if (i > 0 && 0 == path.indexOf(DirectorySeparatorCharJar)) { path = path.substring(1); } pathList.add(path); } return StringUtils.join(pathList.toArray(), DirectorySeparatorCharJar); } /** * 判断目录是否存在,如果不存在就创建目录,如果存在不执行任何操作 * * @param dirPath */ public static File createDirectory(String dirPath) { File file = null; if (StringUtils.isNotBlank(dirPath)) { file = new File(dirPath); if (!file.exists() && !file.isDirectory()) { file.mkdirs(); } } return file; } /** * 删除指定的文件 * * @param filePath 文件物理路径 * @return */ public static boolean deleteFile(String filePath) { boolean success = false; if (StringUtils.isNotBlank(filePath)) { File file = new File(filePath); success = deleteFile(file); file = null; } return success; } /** * 复制文件 * * @param srcFilePath 源文件物理路径 * @param descFilePath 目标文件物理路径 * @throws IOException */ public static void copyFile(String srcFilePath, String descFilePath) throws IOException { File srcFile = new File(srcFilePath); File destFile = new File(descFilePath); FileUtils.copyFile(srcFile, destFile); srcFile = null; destFile = null; }
DateHelper.java
/** * 获取当前系统时间 * * @return 获取当前系统时间 */ public static Date now() { return new GregorianCalendar().getTime(); } /** * 得到自定义格式输出日期的字符串类型 * * @param date * @param format * @return */ public static String toString(Date date, String format) { if (date != null) { return new SimpleDateFormat(format).format(date); } return ""; }
AddImage.html (thymeleaf,Html5上传图片)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head th:replace="Shared/_Layout :: Head(~{this :: title}, ~{this :: .custom-Header})" > <title></title> <script class="custom-Header" src="/Content/H5Uplodify/demo.js"></script> <script class="custom-Header" src="/Content/H5Uplodify/progress.js"></script> <script class="custom-Header" src="/Content/H5Uplodify/zyFile.js"></script> <script class="custom-Header" src="/Content/H5Uplodify/zyUpload.js"></script> <link class="custom-Header" href="/Content/H5Uplodify/zyUpload.css" rel="stylesheet" /> </head> <body> <th:block layout:fragment="Body"> <form id="form"> <table class="form"> <tr> <td class="form-label">图片上传:</td> <td class="form-editor"> <img src='/Images/empty-small.png' height="80" id="imageView" style="margin-left:8px" /> <div id="demo" class="demo"></div> <input type="hidden" name="imageSrc" id="imageSrc" /> </td> </tr> </table> </form> </th:block> </body> </html>