package com.hotent.file.attachmentService; import com.hotent.base.attachment.Attachment; import com.hotent.base.attachment.AttachmentService; import com.hotent.base.attachment.MultipartFileParam; import com.hotent.base.attachment.UploadShardResult; import com.hotent.base.exception.BaseException; import com.hotent.base.util.AppUtil; import com.hotent.base.util.BeanUtils; import com.hotent.base.util.StringUtil; import com.hotent.file.model.FtpEntity; import com.hotent.file.model.UploadProperties; import com.hotent.file.service.FlowUploadPropertiesService; import com.hotent.file.util.AppFileUtil; import org.apache.commons.net.ftp.*; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.*; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @Service public class FtpAttachmentServiceImpl implements AttachmentService{ @Resource FlowUploadPropertiesService flowUploadPropertiesService; //连接FTP服务器 private void connect(FtpEntity ftpEntity, FTPClient ftp){ try { int reply; ftp.connect(ftpEntity.getUrl(), ftpEntity.getPort()); FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT); conf.setServerLanguageCode("zh"); boolean loginResult = ftp.login(ftpEntity.getUsername(), ftpEntity.getPassword()); if(loginResult){ // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK). if (FTPReply.isPositiveCompletion(ftp.sendCommand("OPTS UTF8", "ON"))) { ftpEntity.setLOCAL_CHARSET("UTF-8"); } ftp.setControlEncoding(ftpEntity.getLOCAL_CHARSET()); ftp.enterLocalPassiveMode(); // 设置被动模式 //设置为二进制文件,避免乱码 ftp.setFileType(FTPClient.BINARY_FILE_TYPE); } reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); } } catch (Exception e) { e.printStackTrace(); } } @Override public void upload(Attachment attachment, InputStream inputStream,String propertiesId) throws Exception { FtpEntity ftpEntity = AppUtil.getBean(FtpEntity.class); FTPClient ftp = new FTPClient(); //如果是流程附件,则获取其上传配置信息 ftpEntity = initUploadProperties(propertiesId,attachment,ftpEntity,true); String path = attachment.getFilePath(); String fileName = attachment.getEntryptName()?attachment.getId():attachment.getFileName() + "." + attachment.getExtensionName(); path = replaceFileSeparator(path); path = new String(path.getBytes(ftpEntity.getLOCAL_CHARSET()), ftpEntity.getSERVER_CHARSET()); //fileName = new String(fileName.getBytes(LOCAL_CHARSET), SERVER_CHARSET); validConnection(ftpEntity,ftp); // 转到指定上传目录,没有该目录则创建 CreateDirecroty(path,ftp); ftp.setFileType(FTP.BINARY_FILE_TYPE); boolean result = ftp.storeFile(fileName, inputStream); if (!result) { throw new RuntimeException("上传文件失败"); } // 关闭输入流 inputStream.close(); } @Override public void download(Attachment attachment, OutputStream outStream,String propertiesId) throws Exception{ if(!this.downloadFile(attachment, outStream, propertiesId)){ throw new BaseException("要下载的文件不存在"); } outStream.close(); } /** * 下载ftp文件 * @param attachment 附件信息 * @param outStream 输出流 * @param propertiesId 流程附件配置ID * @throws Exception */ private Boolean downloadFile(Attachment attachment, OutputStream outStream,String propertiesId) throws Exception{ //如果是流程附件,则获取其上传配置信息 FtpEntity ftpEntity = AppUtil.getBean(FtpEntity.class); FTPClient ftp = new FTPClient(); ftpEntity = initUploadProperties(propertiesId,attachment,ftpEntity,false); validConnection(ftpEntity,ftp); String path = attachment.getFilePath(); path = replaceFileSeparator(path); String fileName = attachment.getEntryptName()?attachment.getId():attachment.getFileName() + "." + attachment.getExtensionName(); // 编码转换,避免上传到服务器上时出现中文乱码 path = getFtpPath(path); path = new String(path.getBytes(ftpEntity.getLOCAL_CHARSET()), ftpEntity.getSERVER_CHARSET()); boolean changeResult = ftp.changeWorkingDirectory(path);// 转移到FTP服务器目录 if(!changeResult){ throw new RuntimeException("要下载的文件路径不存在"); } FTPFile[] fs = ftp.listFiles(); boolean tag = false; for (FTPFile ff : fs) { String n = ff.getName(); if (n.equals(fileName)) { tag = true; ftp.retrieveFile(fileName, outStream); break; } } return tag; } @Override public boolean chekckFile(Attachment attachment,String propertiesId) throws Exception{ //如果是流程附件,则获取其上传配置信息 FtpEntity ftpEntity =AppUtil.getBean(FtpEntity.class); FTPClient ftp = new FTPClient(); ftpEntity = initUploadProperties(propertiesId,attachment,ftpEntity,false); boolean ref=true; validConnection(ftpEntity,ftp); String path = attachment.getFilePath(); path = replaceFileSeparator(path); String fileName = attachment.getEntryptName()?attachment.getId():attachment.getFileName() + "." + attachment.getExtensionName(); // 编码转换,避免上传到服务器上时出现中文乱码 path = getFtpPath(path); path = new String(path.getBytes(ftpEntity.getLOCAL_CHARSET()), ftpEntity.getSERVER_CHARSET()); boolean changeResult = ftp.changeWorkingDirectory(path);// 转移到FTP服务器目录 if(!changeResult){ ref=false; } FTPFile[] fs = ftp.listFiles(); boolean tag = false; for (FTPFile ff : fs) { String n = ff.getName(); if (n.equals(fileName)) { tag = true; break; } } if(!tag){ ref=false; } return ref; } @Override public void remove(Attachment attachment,String propertiesId) throws Exception { //如果是流程附件,则获取其上传配置信息 FtpEntity ftpEntity =AppUtil.getBean(FtpEntity.class); FTPClient ftp = new FTPClient(); ftpEntity = initUploadProperties(propertiesId,attachment,ftpEntity,false); validConnection(ftpEntity,ftp); String path = attachment.getFilePath(); path = replaceFileSeparator(path); String fileName = attachment.getEntryptName()?attachment.getId():attachment.getFileName()+ "." + attachment.getExtensionName(); ftp.deleteFile(path + ftpEntity.getSeparator() + fileName); } //验证连接 private void validConnection(FtpEntity ftpEntity,FTPClient ftp){ try{ if(!ftp.isConnected()||!ftp.isRemoteVerificationEnabled()||!ftp.sendNoOp()){ connect(ftpEntity,ftp); } // 重置当前目录到根目录 ftp.changeWorkingDirectory(File.separator); } catch(Exception e){ connect(ftpEntity,ftp); } } /*//转移FTP文件目录位置(不存在的目录会自动创建) private void changeDirectory(String path) throws Exception{ boolean changeResult = ftp.changeWorkingDirectory(path); //转移失败,则该目录不存在 if(!changeResult){ String errorMsg = "上传文件时,创建文件路径失败"; //创建目录 int mkd = ftp.mkd(path); if(mkd!=257){ throw new RuntimeException(errorMsg); } //转移到该目录 changeResult = ftp.changeWorkingDirectory(path); if(!changeResult){ throw new RuntimeException(errorMsg); } } }*/ /** * 创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建 * @param remote * @return * @throws IOException */ private boolean CreateDirecroty(String remote,FTPClient ftp) throws IOException { boolean success = true; remote = getFtpPath(remote); String separator = "/"; String directory = remote + separator; // 如果远程目录不存在,则递归创建远程服务器目录 if (!directory.equalsIgnoreCase(separator) && !changeWorkingDirectory(new String(directory),ftp)) { int start = 0; int end = 0; if (directory.startsWith(separator)) { start = 1; } else { start = 0; } end = directory.indexOf(separator, start); String path = ""; String paths = ""; while (true) { String subDirectory = new String(remote.substring(start, end).getBytes("GBK"), "iso-8859-1"); path = path + separator + subDirectory; if (!existFile(path,ftp)) { if (makeDirectory(subDirectory,ftp)) { changeWorkingDirectory(subDirectory,ftp); } else { System.out.println("创建目录[" + subDirectory + "]失败"); changeWorkingDirectory(subDirectory,ftp); } } else { changeWorkingDirectory(subDirectory,ftp); } paths = paths + separator + subDirectory; start = end + 1; end = directory.indexOf(separator, start); // 检查所有目录是否创建完毕 if (end <= start) { break; } } } return success; } /** * 改变目录路径 * @param directory * @return */ private boolean changeWorkingDirectory(String directory,FTPClient ftp) { boolean flag = true; try { flag = ftp.changeWorkingDirectory(directory); if (flag) { System.out.println("进入文件夹" + directory + " 成功!"); } else { System.out.println("进入文件夹" + directory + " 失败!开始创建文件夹"); } } catch (IOException ioe) { ioe.printStackTrace(); } return flag; } /** * 判断ftp服务器文件是否存在 * @param path * @return * @throws IOException */ private boolean existFile(String path,FTPClient ftp) throws IOException { boolean flag = false; FTPFile[] ftpFileArr = ftp.listFiles(path); if (ftpFileArr.length > 0) { flag = true; } return flag; } /** * 创建目录 * @param dir * @return */ private boolean makeDirectory(String dir,FTPClient ftp) { boolean flag = true; try { flag = ftp.makeDirectory(dir); if (flag) { System.out.println("创建文件夹" + dir + " 成功!"); } else { System.out.println("创建文件夹" + dir + " 失败!"); } } catch (Exception e) { e.printStackTrace(); } return flag; } private String replaceFileSeparator(String path){ // 替换路径中的分隔符 String ftpFormatPath = regReplace(path, File.separator); // 替换文件名,只保留路径 ftpFormatPath = ftpFormatPath.replaceAll("/\\w+\\.?(\\w+)?(\\s+)?$", ""); if(path.equals(ftpFormatPath)){ ftpFormatPath = getFtpPath(ftpFormatPath); ftpFormatPath = ftpFormatPath.replaceAll("/\\w+\\.?(\\w+)?(\\s+)?$", ""); ftpFormatPath = ftpFormatPath.replaceAll("/", "\\\\"); } return ftpFormatPath; } private String regReplace(String str, String replaceChar){ StringBuffer resultString = new StringBuffer(); try { Pattern regex = Pattern.compile("[\\|/]"); Matcher regexMatcher = regex.matcher(str); while (regexMatcher.find()) { regexMatcher.appendReplacement(resultString, replaceChar); } regexMatcher.appendTail(resultString); } catch (PatternSyntaxException ex) { ex.printStackTrace(); } return resultString.toString(); } @Override public String getStoreType() { return "ftp"; } /** * 根据配置id获取文件上传配置 * @param propertiesId * @return */ private FtpEntity initUploadProperties(String propertiesId,Attachment defaultFile,FtpEntity ftpEntity,boolean isUpload){ if(StringUtil.isNotEmpty(propertiesId)){ UploadProperties uploadProperties = flowUploadPropertiesService.getUploadProperties(propertiesId); if(BeanUtils.isNotEmpty(uploadProperties)){ String location = uploadProperties.getLocation(); if(isUpload && StringUtil.isNotEmpty(location)){ location = location.replace("/", "\\"); defaultFile.setFilePath(location+defaultFile.getFilePath()); } FtpEntity ftpEntity2 =new FtpEntity(); ftpEntity2.setUrl(uploadProperties.getFtpUrl()); ftpEntity2.setPort(uploadProperties.getFtpPort()); ftpEntity2.setUsername(uploadProperties.getFtpUserName()); ftpEntity2.setPassword(uploadProperties.getFtpPassword()); defaultFile.setEntryptName(uploadProperties.getEncryptName()== 0 ? false : true); return ftpEntity2; }else if(isUpload){ String sysPath = AppFileUtil.getAttachPath(); if(StringUtil.isNotEmpty(sysPath)){ sysPath = sysPath.replace("/", "\\"); defaultFile.setFilePath(sysPath+defaultFile.getFilePath()); } } return ftpEntity; } return ftpEntity; } @Override public byte[] getFileBytes(Attachment attachment) throws Exception { String propertiesId = BeanUtils.isNotEmpty(attachment)?attachment.getProp6():""; try(ByteArrayOutputStream outStream = new ByteArrayOutputStream()){ this.downloadFile(attachment, outStream, propertiesId); return outStream.toByteArray(); } } private String getFtpPath(String path){ if(StringUtil.isNotEmpty(path)){ path = path.replaceAll("\\\\", "/"); } return path; } @Override public UploadShardResult uploadByShard(MultipartFileParam multipartFileParam, Attachment attachment, String propertiesId) throws Exception { return null; } @Override public Map generatePolicy(Attachment attachment, String propertiesId) { return null; } @Override public String getUrl(Attachment attachment, String propertiesId) throws UnsupportedEncodingException { return null; } @Override public InputStream getFileInputStream(Attachment attachment) throws FileNotFoundException { return null; } @Override public String getFilePath(String account, String fileName) { return AppFileUtil.getFilePath(account,fileName); } }