FtpAttachmentServiceImpl.java 13.3 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
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<String,Object> 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);
	}
}