上传遇到这种情况,去FTP服务器上看看,如果文件也确实存在,只不过内容是空的。最简单的办法就是试试关闭服务器防火墙(直接在服务器上敲命令或手动关闭即可),如果关闭防火墙,文件能正常上传,那就好办了。ftp默认的上传模式是主动上传,如果防火墙不能关闭,在代码里上传模式改成被动上传就行。
先看代码:
public Result uploadFile(@RequestParam(value = "file") MultipartFile file) {
try {
String fileName = file.getOriginalFilename();
String suffixName = fileName.substring(fileName.indexOf(".") + 1);
Map
这里因为上传服务要做兼容,config对象的子类为oss和ftp两个对象。
/**
* @param fileContent byte[]文件字节数组对象
* @param suffixName 文件名后缀名
* @param fileName 文件前缀名
* @param isTemp 是否加入临时目录标识
*/
public static String uploadFile(byte[] fileContent, String suffixName, boolean isTemp,String fileName) throws Exception {
StringBuilder str = new StringBuilder();
if (isTemp) {
str.append("temp").append("/");
}
//如果有业务号或者id也可以拼进去
if (StringUtil.isNotEmpty(fileName)) {
str.append(fileName).append(".").append(suffixName);
}else{//拼接日期和随机数
str.append(DateUtil.getYear()).append("/")
.append(DateUtil.getMonth()).append("/")
.append(DateUtil.getDay()).append("/")
.append(System.currentTimeMillis())
.append(new Random().nextInt(999))
.append(".").append(suffixName);
}
String name = str.toString();
//判断下用什么服务器做文件管理
Config config;
if ("ftp".equals(GlobalParamConfig.FILE_STORY_WAY)) {
String model = GlobalParamConfig.FILE_FTP_MODEL;//这里是从nacos获取模式配置,也可以用字典等等。
if(DictDefinition.FILE_FTP_PASSIVE_MODE.equals(model)){//被动模式
config = new FtpConfig("host", "ip", "username", "password", model);
}else {//默认为主动模式
config = new FtpConfig("host", "ip", "username", "password", null);
}
} else if ("oss".equals(GlobalParamConfig.FILE_STORY_WAY)) {//用oss阿里云
config = new OSSConfig("url", "accesskeyid","bucket","accesskeysecret","isencrypt");
} else {
throw new CrmException("文件上传与下载方式,服务配置错误");
}
FileStore fileStore = new FtpUtil(config);
boolean storeFile = fileStore.storeFile(name, new ByteArrayInputStream(fileContent));
return name;
}
这里创建ftp的客户端,做一些常规设置,然后判断是否把上传模式改为被动模式。
public FtpUtil(String ip, int port, String userName, String password, String model) {
try {
//创建FTPClient连接,并登录
this.ftpClient = new FTPClient();
this.ftpClient.connect(ip, port);
this.ftpClient.setControlEncoding("GBK");
FTPClientConfig config = new FTPClientConfig("WINDOWS");
config.setServerLanguageCode("zh");
this.ftpClient.login(userName, password);
if (model != null && !"".equals(model)) {//判断设置被动模式
this.ftpClient.enterLocalPassiveMode();
}
//reply是连接后,ftp给的整数值回复码,判断回复码是否正常
int reply = this.ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
this.ftpClient.disconnect();
throw new Exception("连接ftp服务器出错,请联系管理员处理!");
}
} catch (Exception var8) {
System.err.println("%%%% Error Creating FTPConnection %%%%");
log.severe("连接ftp服务器出错!");
var8.printStackTrace();
}
}
后面就是做上传文件操作了。这里有两种方法实现,我这边用的第二个方法。
public boolean storeFile(String path, InputStream inputStream) {
boolean success = false;
String fileType = FileUtils.getFileType(path);
String tempFile = FileUtils.creteTempPath(fileType);
try {
FileUtils.writeBytesToFile(input2byte(inputStream), tempFile);
byte[] encrypt = AES.encrypt(FileUtils.readBytesFromFile(new File(tempFile)));
FileUtils.writeBytesToFile(encrypt, tempFile);
success = this.ftpUtil.upload(new FileInputStream(new File(tempFile)), path);
} catch (Exception var7) {
var7.printStackTrace();
}
FileUtils.deleteFile(tempFile);
this.ftpUtil.disConFtp();
return success;
}
public boolean storeFile(String path, InputStream inputStream) {
boolean success = ftpUtil.upload(inputStream, path);
//关闭ftp连接
ftpUtil.disConFtp();
return success;
}
通过upload把文件上传到ftp服务器上。
public boolean upload(InputStream fis, String targetFile) {
targetFile = "/" + targetFile;
String targetPath = targetFile.substring(0, targetFile.lastIndexOf("/"));
String fileName = targetFile.substring(targetFile.lastIndexOf("/") + 1);
boolean success = false;
try {
this.mkDir(targetPath);
this.ftpClient.setFileType(2);
success = this.ftpClient.storeFile(fileName, fis);//FTPClient自带的上传文件方法
} catch (IOException var10) {
var10.printStackTrace();
log.severe("上传出错,请重新上传");
} finally {
IOUtils.closeQuietly(fis);
}
//因为调用upload的方法,后面有关闭ftp连接,这里直接返回就可以了
return success;
}
//完成操作,断开连接
public void disConFtp() {
try {
if (null != this.ftpClient) {
this.ftpClient.logout();
if (this.ftpClient.isConnected()) {
this.ftpClient.disconnect();
}
}
} catch (IOException var2) {
log.severe("退出ftp异常,检查网络!");
var2.printStackTrace();
}
}
//判断文件路径,切换到该路径
private synchronized void mkDir(String filePath) throws IOException {
String[] fileName = filePath.split("/");
for(int i = 0; i < fileName.length; ++i) {
String targetPath = fileName[i];
if (targetPath != null && !"".equals(targetPath)) {
//判断路径不为空,就切换到该目录下
boolean temp = this.ftpClient.changeWorkingDirectory(targetPath);
if (!temp) {
//目录不存在就创建,然后切换到该目录下
this.ftpClient.makeDirectory(targetPath);
this.ftpClient.changeWorkingDirectory(targetPath);
}
}
}
}
这差不多快是全部的ftp上传代码了,最后说下这个主动和被动上传吧。
主动上传:对FTP服务器的管理有利,但对客户端的管理不利。因为FTP服务器企图与客户端的高位随机端口建立连接,而这个端口很有可能被客户端的防火墙阻塞掉。
被动上传:对FTP客户端的管理有利,但对服务器端的管理不利。因为客户端要与服务器端建立两个连接,其中一个连到一个高位随机端口,而这个端口很有可能被服务器端的防火墙阻塞掉。
既然FTP服务器的管理员需要他们的服务器有最多的客户连接,那么必须得支持被动FTP。我们可以通过为FTP服务器指定一个有限的端口范围来减小服务器高位端口的暴露。这样,不在这个范围的任何端口会被服务器的防火墙阻塞。虽然这没有消除所有针对服务器的危险,但它大大减少了危险。
主动或被动模式都是有利有弊,需要考虑相应的场景采用适合的模式。一般内网用被动模式 ,外网连接时用主动模式,服务器相应改动,使用应当参考实际应用场景。