以前的文件上传都是之前前辈写的,现在自己来写一个,大家可以看看,有什么问题可以在评论中提出来。
写的这个文件上传是在spring boot 2.0中测试的,测试了,可以正常上传,下面贴代码
第一步:引入依赖
这里我用的是maven构建项目,spring boot 的相关pom我就不贴了,我这里贴我额外引入的。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- Apache Commons FileUpload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <!-- Apache Commons IO --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <!-- thumbnailator 图片压缩工具 --> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.8</version> </dependency>
第二步:编写上传返回结果实体 FileResult.java
import lombok.Data; /** * 文件上传返回的数据实体 * * @author lixingwu */ @Data public class FileResult {
// 文件名 private String fileName;
// 扩展名 private String extName;
// 文件大小,字节 private Long fileSize;
// 文件存储在服务器的相对地址 private String serverPath; }
第三步:编写 PropertiesUtils.java 和 custom.properties
import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * 读取properties文件 * * @author lixingwu */ public class PropertiesUtils { private Properties properties; private static PropertiesUtils propertiesUtils = new PropertiesUtils(); /** * 私有构造,禁止直接创建 */ private PropertiesUtils() { properties = new Properties(); InputStream in = PropertiesUtils.class.getClassLoader() .getResourceAsStream("custom.properties"); try { properties.load(in); } catch (IOException e) { e.printStackTrace(); } } /** * 获取单例 * * @return PropertiesUtils */ public static PropertiesUtils getInstance() { if (propertiesUtils == null) { propertiesUtils = new PropertiesUtils(); } return propertiesUtils; } /** * 根据属性名读取值 * * @param name 名称 */ public Object getProperty(String name) { return properties.getProperty(name); } /*************************************************************************/ /*****************************读取属性,封装字段**************************/ /*************************************************************************/ /** * 是否调试模式 */ public Boolean isDebug() { return "true".equals(properties.getProperty("isDebug")); } public String getAttachmentServer() { return properties.getProperty("attachmentServer"); } public String getAttachmentPath() { return properties.getProperty("attachmentPath"); } public String getAttachmentGainPpath() { return properties.getProperty("attachmentGainPath"); } public static void main(String[] args) { PropertiesUtils pro = PropertiesUtils.getInstance(); String value = String.valueOf(pro.getProperty("custom.properties.name").toString()); System.out.println(value); } }
custom.properties(具体路径,根据自己项目进行修改)
# 自定义 属性文件,可使用 PropertiesUtils.java 来读取 custom.properties.name=custom.properties isDebug=true #附件地址 attachmentServer=www.baidu.con/static
#服务器静态文件地址 attachmentPath=/var/www/html #服务器存储文件的地址
attachmentGainPath=/var/www/html/upload
第四步:编写 FileuploadUtil.java
package com.zhwlt.logistics.utils; import com.zhwlt.logistics.pojo.system.FileResult; import net.coobird.thumbnailator.Thumbnails; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.*; /** * 文件上传工具类(修改了bug 2019-0105) * * @author lixingwu */ public class FileuploadUtil { /** * 属性配置 */ private static PropertiesUtils pro = PropertiesUtils.getInstance(); /** * 方法描述:根据文件的绝对路径创建一个文件对象. * 创建时间:2018-10-19 09:32:34 * * @param filePath 文件的绝对路径 * @return 返回创建的这个文件对象 * @author "lixingwu" */ public static File createFile(String filePath) throws IOException { // 获取文件的完整目录 String fileDir = FilenameUtils.getFullPath(filePath); // 判断目录是否存在,不存在就创建一个目录 File file = new File(fileDir); if (!file.isDirectory()) { //创建失败返回null if (!file.mkdirs()) { throw new IOException("文件目录创建失败..."); } } // 判断这个文件是否存在,不存在就创建 file = new File(filePath); if (!file.exists()) { if (!file.createNewFile()) { throw new IOException("目标文件创建失败..."); } } return file; } /** * 方法描述:判断extension中是否存在extName * 创建时间:2018-10-20 20:46:18 * * @param extension 使用逗号隔开的字符串,精确匹配例如:txt,jpg,png,zip * @param extName 文件的后缀名 * @author "lixingwu" */ private static void isContains(String extension, String extName) { if (StringUtils.isNotEmpty(extension)) { // 切割文件扩展名 String[] exts = StringUtils.split(extension, ","); if (ArrayUtils.isNotEmpty(exts)) { assert exts != null; List<String> extList = Arrays.asList(exts); //判断 if (!extList.contains(extName)) { throw new RuntimeException("上传文件的类型只能是:" + extension); } } else { // 判断文件的后缀名是否为extension if (!extension.equalsIgnoreCase(extName)) { throw new RuntimeException("上传文件的类型只能是:" + extension); } } } } /** * 方法描述:处理上传的图片 * 创建时间:2018-10-20 20:46:18 * * @param serverPath 图片的绝对路径 * @param childFile 子文件夹 * @param extName 文件的后缀 * @author "lixingwu" */ private static String thumbnails(String serverPath, String childFile, String extName) throws IOException { // 压缩后的相对路径文件名 String toFilePath = getDestPath(childFile, extName); // scale:图片缩放比例 // outputQuality:图片压缩比例 // toFile:图片位置 // outputFormat:文件输出后缀名 // Thumbnails 如果用来压缩 png 格式的文件,会越压越大, // 得把png格式的图片转换为jpg格式 if ("png".equalsIgnoreCase(extName)) { // 由于outputFormat会自动在路径后加上后缀名,所以移除以前的后缀名 String removeExtensionFilePath = FilenameUtils.removeExtension(toFilePath); Thumbnails.of(serverPath).scale(1f) .outputQuality(0.5f) .outputFormat("jpg") .toFile(getServerPath(removeExtensionFilePath)); toFilePath = removeExtensionFilePath + ".jpg"; } else { Thumbnails.of(serverPath).scale(1f).outputQuality(0.5f) .toFile(getServerPath(toFilePath)); } // 删除被压缩的文件 FileUtils.forceDelete(new File(serverPath)); return toFilePath; } /** * 方法描述:生成文件文件名 * 创建时间:2018-10-20 20:46:18 * * @param childFile 子目录 * @param extName 后缀名 * @author "lixingwu" */ private static String getDestPath(String childFile, String extName) { //规则: 子目录/年月日_随机数.后缀名 String sb = childFile + "/" + DateUtil.formatDate(new Date(), DateUtil.DATE_FORMAT_SHORT) + "_" + Tools.getRandom() + "." + extName; return sb; } /** * 方法描述:生成文件在的实际的路径 * 创建时间:2018-10-20 20:46:18 * * @param destPath 文件的相对路径 * @author "lixingwu" */ private static String getServerPath(String destPath) { // 文件分隔符转化为当前系统的格式 return FilenameUtils.separatorsToSystem(pro.getAttachmentGainPpath() + destPath); } /** * 方法描述:上传文件. * 创建时间:2018-10-19 13:09:19 * * @param multipartFile 上传的文件对象,必传 * @param childFile 上传的父目录,为空直接上传到指定目录 (会在指定的目录下新建该目录,例如:/user/1023) * @param extension 允许上传的文件后缀名,为空不限定上传的文件类型 (使用逗号隔开的字符串,精确匹配例如:txt,jpg,png,zip) * @param isImage 上传的是否是图片,如果是就会进行图片压缩;如果不希望图片被压缩,则传false,让其以文件的形式来保存 * @return the file result * @throws IOException 异常信息应返回 * @author "lixingwu" */ private static FileResult saveFile(MultipartFile multipartFile, String childFile, String extension, Boolean isImage) throws IOException { if (null == multipartFile || multipartFile.isEmpty()) { throw new IOException("上传的文件对象不存在..."); } // 文件名 String fileName = multipartFile.getOriginalFilename(); // 文件后缀名 String extName = FilenameUtils.getExtension(fileName); if (StringUtils.isEmpty(extName)) { throw new RuntimeException("文件类型未定义不能上传..."); } // 判断文件的后缀名是否符合规则 isContains(extension, extName); // 创建目标文件的名称,规则请看destPath方法 String destPath = getDestPath(childFile, extName); // 文件的实际路径 String serverPath = getServerPath(destPath); // 创建文件 File destFile = createFile(serverPath); // 保存文件 multipartFile.transferTo(destFile); // 拼装返回的数据 FileResult result = new FileResult(); //如果是图片,就进行图片处理 if (BooleanUtils.isTrue(isImage)) { // 图片处理 String toFilePath = thumbnails(serverPath, childFile, extName); // 得到处理后的图片文件对象 File file = new File(getServerPath(toFilePath)); // 压缩后的文件后缀名 String extExtName = FilenameUtils.getExtension(toFilePath); // 源文件=源文件名.压缩后的后缀名 String extFileName = FilenameUtils.getBaseName(fileName) + "." + FilenameUtils.getExtension(toFilePath); result.setFileSize(file.length()); result.setServerPath(toFilePath); result.setFileName(extFileName); result.setExtName(extExtName); } else { result.setFileSize(multipartFile.getSize()); result.setFileName(fileName); result.setExtName(extName); result.setServerPath(destPath); } return result; } /** * 方法描述:上传文件. * 创建时间:2018-10-19 13:09:19 * * @param multipartFile 上传的文件对象,必传 * @param childFile 上传的父目录,为空直接上传到指定目录 (会在指定的目录下新建该目录,例如:/user/1023) * @param extension 允许上传的文件后缀名,为空不限定上传的文件类型 (使用逗号隔开的字符串,精确匹配例如:txt,jpg,png,zip) * @return the file result * @throws IOException 异常信息应返回 * @author "lixingwu" */ public static FileResult saveFile(MultipartFile multipartFile, String childFile, String extension) throws IOException { return saveFile(multipartFile, childFile, extension, false); } /** * 方法描述:上传图片. * 创建时间:2018-10-19 13:09:19 * * @param multipartFile 上传的文件对象,必传 * @param childFile 上传的父目录,为空直接上传到指定目录 (会在指定的目录下新建该目录,例如:/user/1023) * @param extension 允许上传的文件后缀名,为空不限定上传的文件类型 (使用逗号隔开的字符串,精确匹配例如:txt,jpg,png,zip) * @return the file result * @throws IOException 异常信息应返回 * @author "lixingwu" */ public static FileResult saveImage(MultipartFile multipartFile, String childFile, String extension) throws IOException { return saveFile(multipartFile, childFile, extension, true); } }
第五步:编写 UploadCtl.java (测试可用 Postman)
package com.zhwlt.logistics.controller.system; import com.zhwlt.logistics.controller.base.BaseController; import com.zhwlt.logistics.pojo.system.CommonResult; import com.zhwlt.logistics.utils.FileuploadUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; /** * 上传文件 * * @author lixingwu */ @RestController @RequestMapping("/system") @Api(description = "上传文件类", tags = {"UploadCtl"}) public class UploadCtl extends BaseController{ /** * 方法描述:文件上传,图片也可以使用,但是图片不会被压缩. * 创建时间:2018-10-19 14:10:32 * * @param childFile 上传的父目录 * @param extension 允许上传的文件后缀名 * @author "lixingwu" */ @ApiOperation(value = "文件上传", notes = "图片也可以使用,但是图片不会被压缩") @PostMapping("/uploadFile") public CommonResult uploadFile( MultipartFile multipart, @RequestParam(value = "childFile", required = false, defaultValue = "") String childFile, @RequestParam(value = "extension", required = false, defaultValue = "") String extension ) throws IOException { return resultDataWrapper(FileuploadUtil.saveFile(multipart, childFile, extension)); } /** * 方法描述:图片上传,只能给图片使用,其他文件调用会异常. * 创建时间:2018-10-19 14:10:32 * * @param childFile 上传的父目录 * @param extension 允许上传的文件后缀名 * @author "lixingwu" */ @ApiOperation(value = "图片上传", notes = "只能给图片使用,其他文件调用会异常") @PostMapping("/uploadImage") public CommonResult uploadImage( MultipartFile multipart, @RequestParam(value = "childFile", required = false, defaultValue = "") String childFile, @RequestParam(value = "extension", required = false, defaultValue = "") String extension ) throws IOException { return resultDataWrapper(FileuploadUtil.saveImage(multipart, childFile, extension)); } }