From 4471c29928f204e1fa7f5a2c592c931461624c4e Mon Sep 17 00:00:00 2001 From: Guoqs <123@jsowell.com> Date: Fri, 31 May 2024 15:10:10 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=B8=8A=E4=BC=A0FTP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 1 + .../src/main/resources/application-prd.yml | 1 + .../src/main/resources/application-pre.yml | 1 + .../src/main/resources/application-sit.yml | 1 + jsowell-common/pom.xml | 6 + .../com/jsowell/common/config/FtpConfig.java | 32 +++ .../jsowell/common/util/file/FtpUtils.java | 256 ++++++++++++++++++ 7 files changed, 298 insertions(+) create mode 100644 jsowell-common/src/main/java/com/jsowell/common/config/FtpConfig.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/file/FtpUtils.java diff --git a/jsowell-admin/src/main/resources/application-dev.yml b/jsowell-admin/src/main/resources/application-dev.yml index 9031793ff..99414e12d 100644 --- a/jsowell-admin/src/main/resources/application-dev.yml +++ b/jsowell-admin/src/main/resources/application-dev.yml @@ -193,3 +193,4 @@ remoteUpdate: port: 21 username: jsowellftp password: ZzJeZRB6fDRc + uploadPath: /www/wwwroot/jsowellftp diff --git a/jsowell-admin/src/main/resources/application-prd.yml b/jsowell-admin/src/main/resources/application-prd.yml index ce2acad89..fbe8b4f3f 100644 --- a/jsowell-admin/src/main/resources/application-prd.yml +++ b/jsowell-admin/src/main/resources/application-prd.yml @@ -189,3 +189,4 @@ remoteUpdate: port: 21 username: jsowellftpprd password: ADHJAYinpXEc + uploadPath: /www/wwwroot/jsowellftpprd diff --git a/jsowell-admin/src/main/resources/application-pre.yml b/jsowell-admin/src/main/resources/application-pre.yml index 7c7166bd9..82781d13e 100644 --- a/jsowell-admin/src/main/resources/application-pre.yml +++ b/jsowell-admin/src/main/resources/application-pre.yml @@ -189,3 +189,4 @@ remoteUpdate: port: 21 username: jsowellftpprd password: ADHJAYinpXEc + uploadPath: /www/wwwroot/jsowellftpprd diff --git a/jsowell-admin/src/main/resources/application-sit.yml b/jsowell-admin/src/main/resources/application-sit.yml index 20e31c471..113f047a2 100644 --- a/jsowell-admin/src/main/resources/application-sit.yml +++ b/jsowell-admin/src/main/resources/application-sit.yml @@ -192,3 +192,4 @@ remoteUpdate: port: 21 username: jsowellftp password: ZzJeZRB6fDRc + uploadPath: /www/wwwroot/jsowellftp diff --git a/jsowell-common/pom.xml b/jsowell-common/pom.xml index 388ce3133..00aa07bd2 100644 --- a/jsowell-common/pom.xml +++ b/jsowell-common/pom.xml @@ -53,6 +53,12 @@ commons-lang3 3.12.0 + + + commons-net + commons-net + 3.5 + diff --git a/jsowell-common/src/main/java/com/jsowell/common/config/FtpConfig.java b/jsowell-common/src/main/java/com/jsowell/common/config/FtpConfig.java new file mode 100644 index 000000000..d5364b2f3 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/config/FtpConfig.java @@ -0,0 +1,32 @@ +package com.jsowell.common.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Data +public class FtpConfig { + @Value("${remoteUpdate.server}") + String ip; + + @Value("${remoteUpdate.port}") + int port; + + @Value("${remoteUpdate.username}") + String username; + + @Value("${remoteUpdate.password}") + String password; + + @Value("${remoteUpdate.uploadPath}") + String uploadPath; + + @Value("${remoteUpdate.uploadPath}") + String downPath; + + // 在Controller中用于第二层与第三层路径的拼接 + public static String getPropertyStaffDir() { + return "/propertyStaffImage"; + } +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/file/FtpUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/file/FtpUtils.java new file mode 100644 index 000000000..5fce3a35e --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/file/FtpUtils.java @@ -0,0 +1,256 @@ +package com.jsowell.common.util.file; + + +import com.jsowell.common.config.FtpConfig; +import com.jsowell.common.exception.file.FileSizeLimitExceededException; +import com.jsowell.common.exception.file.InvalidExtensionException; + + +import com.jsowell.common.util.StringUtils; +import com.jsowell.common.util.id.IdUtils; +import org.apache.commons.io.FilenameUtils; + +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPReply; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +@Component +public class FtpUtils { + + /** + * 默认大小 50M + */ + public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; + /** + * 此处静态方法不能用注入的方式初始化 否则为null 因为@Atuowire在初始化此对象之后执行 而调用静态方法不会初始化对象 + */ + static FtpConfig ftpConfig; + + @Autowired + FtpConfig ftp; + + @PostConstruct + public void init() { + ftpConfig = this.ftp; + } + + /** + * @param baseDir 上传的路径 为相对路径 + * @param file 要上传到ftp服务器的文件 + */ + public static String upLoad(String baseDir, MultipartFile file) throws Exception { + FTPClient ftp = new FTPClient(); + try { + /** 1. 检查文件大小和扩展名是否符合要求*/ + assertFile(file); + /** 2. 产生新的文件名,目的使得文件名统一为英文字符加数字;fileName包含文件后缀名*/ + String fileName = reBuildFileName(file); + /** 3. 连接ftp服务器*/ + ftp.connect(ftpConfig.getIp(), ftpConfig.getPort()); + ftp.login(ftpConfig.getUsername(), ftpConfig.getPassword()); + if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) { + // 不合法时断开连接 + ftp.disconnect(); + throw new IOException("ftp连接异常,异常码为:" + ftp.getReplyCode()); + } + String path = ftpConfig.getUploadPath() + baseDir; + String[] dirs = path.split("/"); + ftp.changeWorkingDirectory("/"); + /** 4. 判断ftp服务器目录是否存在 不存在则创建*/ + for (int i = 0; i < dirs.length && dirs != null; i++) { + if (!ftp.changeWorkingDirectory(dirs[i])) { + if (ftp.makeDirectory(dirs[i])) { + if (!ftp.changeWorkingDirectory(dirs[i])) + throw new Exception("打开文件夹" + dirs[i] + "失败"); + } else { + throw new Exception("创建文件夹" + dirs[i] + "失败"); + } + } + } + /** 5.切换ftp文件操作目录*/ + ftp.changeWorkingDirectory(path); + /** 6.上传文件*/ + // 设置文件类型,二进制 + ftp.setFileType(FTPClient.BINARY_FILE_TYPE); + // 设置缓冲区大小 + ftp.setBufferSize(3072); + // 上传文件 + ftp.storeFile(fileName, file.getInputStream()); + // 登出服务器 + ftp.logout(); + return baseDir + "/" + fileName; + } catch (Exception e) { + throw new Exception(e.getMessage(), e); + } finally { + /** 关闭*/ + // 判断连接是否存在 + if (ftp.isConnected()) { + // 断开连接 + ftp.disconnect(); + } + } + + } + + /** + * @param baseDir ftp服务器文件路径 为相对路径 使用数据库中的url路径(ftp存在共享文件夹) + * @param fileName 文件名 + * @param localDir web服务器本地存储路径 为相对路径 使用数据库中的url路径 + * @description: 从ftp服务器上下载文件到本地 + */ + public static boolean downLoad(String localDir, String baseDir, String fileName) { + boolean result = false; + String localPath = ftpConfig.getDownPath() + localDir; + String ftpPath = ftpConfig.getUploadPath() + baseDir; + FTPClient ftp = new FTPClient(); + OutputStream os = null; + try { + // 连接至服务器,端口默认为21时,可直接通过URL连接 + ftp.connect(ftpConfig.getIp(), ftpConfig.getPort()); + // 登录服务器 + ftp.login(ftpConfig.getUsername(), ftpConfig.getPassword()); + // 判断返回码是否合法 + if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) { + // 不合法时断开连接 + ftp.disconnect(); + // 结束程序 + return result; + } + // 设置文件操作目录 + ftp.changeWorkingDirectory(ftpPath); + // 设置文件类型,二进制 + ftp.setFileType(FTPClient.BINARY_FILE_TYPE); + // 设置缓冲区大小 + ftp.setBufferSize(3072); + // 设置字符编码 + ftp.setControlEncoding("UTF-8"); + // 构造本地文件夹 + File localFilePath = new File(localPath); + if (!localFilePath.exists()) { + localFilePath.mkdirs(); + } + // 构造本地文件对象 + File localFile = new File(localPath + "/" + fileName); + // 获取文件操作目录下所有文件名称 + String[] remoteNames = ftp.listNames(); + // 循环比对文件名称,判断是否含有当前要下载的文件名 + for (String remoteName : remoteNames) { + if (fileName.equals(remoteName)) { + result = true; + } + } + // 文件名称比对成功时,进入下载流程 + if (result) { + // 构造文件输出流 + os = new FileOutputStream(localFile); + // 下载文件 写入到输出流中 + result = ftp.retrieveFile(fileName, os); + // 关闭输出流 + os.close(); + } + // 登出服务器 + ftp.logout(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + // 判断输出流是否存在 + if (null != os) { + // 关闭输出流 + os.close(); + } + // 判断连接是否存在 + if (ftp.isConnected()) { + // 断开连接 + ftp.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return result; + } + + /** + * @param realFile: web服务器本地文件 + * @desecription: 删除web服务器本地文件 + */ + public static boolean delrealFile(String realFile) { + File file = new File(realFile); + if (file.exists() && file.isFile()) { + if (file.delete()) { + // System.out.println("删除成功"); + return true; + } else { + System.out.println("删除失败"); + return false; + } + } else { + System.out.println("删除" + realFile + "文件不存在或者不是一个文件类型"); + return false; + } + } + + /** + * @Description: 判断文件大小是否超过50M 以及判断文件扩展名是否是image类型 + */ + public static void assertFile(MultipartFile file) throws FileSizeLimitExceededException, InvalidExtensionException { + long size = file.getSize(); + if (size > DEFAULT_MAX_SIZE) { + throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); + } + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + if (!isAllowedExtension(extension)) { + throw new InvalidExtensionException.InvalidImageExtensionException(MimeTypeUtils.IMAGE_EXTENSION, extension, + fileName); + } + } + + /** + * 编码文件名 + */ + public static final String reBuildFileName(MultipartFile file) { + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + fileName = IdUtils.fastUUID() + "." + extension; + return fileName; + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * @return 后缀名 + */ + public static final String getExtension(MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (StringUtils.isEmpty(extension)) { + extension = MimeTypeUtils.getExtension(file.getContentType()); + } + return extension; + } + + /** + * 判断MIME类型是否是允许的Image类型 + * + * @param extension + * @return + */ + public static final boolean isAllowedExtension(String extension) { + for (String str : MimeTypeUtils.IMAGE_EXTENSION) { + if (str.equalsIgnoreCase(extension)) { + return true; + } + } + return false; + } +}