开发项目时经常遇到有附件上传的功能需求,一开始是将附件作为大对象保存到数据库中。但是发现如果附件量大的话会给数据库存储带来压力,且每次移植时大对象很麻烦。后来就尝试着将在应用服务器指定一个文件夹用来保存每次上传的附件文件,但这种做法也有一个缺点每次重新部署时都需要将该文件夹复制出来,以防止被覆盖。经常一不下心就把文件给覆盖掉了,那种感觉是欲哭无泪啊。
最近在网上找到一种解决办法:用tomcat的虚拟路径+ftp来实现文件上传到非应用服务器目录下。
一、设置tomcat虚拟目录
设置tomcat的虚拟目录有两种实现的方式:
(1).修改${tomcat_home}\conf\server.xml文件。
在<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
后面添加
<Context path="/aa" docBase="E:\aa" debug="0" reloadable="true" crossContext="true"></Context>
其中path是指你可以访问的映射名称,docBase指映射的路径。改完后记得重启tomcat
(2).不修改server.xml文件,在conf目录下建立catalina\localhost\aa.xml。aa.xml中文件内容如下:
<Context path="/aa" reloadable="true" docBase="E:\aa" />
注意:其中path的名称必须和文件名称一致
二、安装ftp工具(可以选择windows自带的iis,本人用的是server-U)
安装server-U的过程不再赘述,安装完成后设置域、用户并为用户指定ftp目录(需指定为上面设置的tomcat虚拟目录)。注意开启ftp的被动连接模式,因为在服务器上有防火墙或其他的软件的话主动连接模式是上传不了文件导致一直在等待的状态。被动连接模式在"域详细信息》监听器"目录下设置,见下图(附件1)
三、编写附件上传代码
public class FtpUploadUtil {
private final Log log = LogFactory.getLog(this.getClass());
private static FtpUploadUtil ftpUploadUtil = null;
private final static String IP = ConfigAccess.init().findProp("ftp_ip");
private final static int PORT = Integer.parseInt(ConfigAccess.init().findProp("ftp_port"));
private final static String USERNAME = ConfigAccess.init().findProp("ftp_username");
private final static String PASSWORD = ConfigAccess.init().findProp("ftp_password");
public synchronized static FtpUploadUtil init() {
if(ftpUploadUtil == null){
ftpUploadUtil = new FtpUploadUtil();
}
return ftpUploadUtil;
}
/**
* @company
* @author tao
* @date Apr 10, 2012 3:11:32 PM
* 描述: 将文件上传到FTP服务器上的制定目录下
* @param file 要上传的文件
* @param path 文件路径
* @param filename 文件名称
* @return
* @throws Exception
*/
public boolean uploadFile(File file,String path, String filename)throws Exception {
boolean success = false;
FTPClient ftp = new FTPClient();
try {
int reply;
FileInputStream in = new FileInputStream(file);
ftp.connect(IP, PORT);//连接FTP服务器
//如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftp.login(USERNAME, PASSWORD);//登录
// ftp.setControlEncoding("GBK");
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return success;
}
// ftp.changeWorkingDirectory(path);
if (CreateDirecroty(path,ftp)) {
ftp.enterLocalPassiveMode();//设置为被动模式传输,否则程序部署到服务器上后选择上传的文件保存后一直处在运行中(不动了,进度条也走得很慢)
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);//缺省的传输模式应该是ASCII,传输图片时需要binary
success = ftp.storeFile(filename, in);
in.close();
ftp.logout();
// success = true;
}else{
log.error("动态创建文件夹失败了!!");
throw new Exception("文件上传失败!!");
}
} catch (IOException e) {
log.error("文件上传失败!!",e);
throw new Exception("文件上传失败!!",e);
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
log.error("文件上传失败!!",ioe);
throw new Exception("文件上传失败!!",ioe);
}
}
}
return success;
}
public boolean downFile(String remotePath,String fileName,String localPath) throws Exception {
boolean success = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(IP, PORT);
//如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftp.login(USERNAME, PASSWORD);//登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return success;
}
ftp.changeWorkingDirectory(remotePath);//转移到FTP服务器目录
FTPFile[] fs = ftp.listFiles();
for(FTPFile ff:fs){
if(ff.getName().equals(fileName)){
File localFile = new File(localPath+"/"+ff.getName());
OutputStream is = new FileOutputStream(localFile);
ftp.retrieveFile(ff.getName(), is);
is.close();
}
}
ftp.logout();
success = true;
} catch (IOException e) {
log.error("文件下载失败!!",e);
throw new Exception("文件下载失败!!",e);
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
log.error("文件下载失败!!",ioe);
throw new Exception("文件下载失败!!",ioe);
}
}
}
return success;
}
/**
* @company
* @author tao
* @date Apr 10, 2012 5:35:22 PM
* 描述:如果目录不存在动态的创建目录
* @param path
* @param ftp
* @return
* @throws IOException
*/
public boolean CreateDirecroty(String path,FTPClient ftp) throws IOException {
boolean success = true;
// 如果远程目录不存在,则递归创建远程服务器目录
if (!path.equalsIgnoreCase("/")&& !ftp.changeWorkingDirectory(new String(path))) {
int start = 0;
int end = 0;
if (path.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = path.indexOf("/", start);
while (true) {
String subDirectory = new String(path.substring(start, end));
if (!ftp.changeWorkingDirectory(subDirectory)) {
if (ftp.makeDirectory(subDirectory)) {
ftp.changeWorkingDirectory(subDirectory);
} else {
System.out.println("创建目录失败");
success = false;
return success;
}
}
start = end + 1;
end = path.indexOf("/", start);
// 检查所有目录是否创建完毕
if (end <= start) {
break;
}
}
}
return success;
}
}