通过RMI下载UNIX系统上的文件

Server端:
1. 定义远程通讯的接口和与接口相关的类(这里只有RemoteFileInfo.java)。该接口必须继承接口Remote,它里面的方法都要抛出RemoteException异常。
FileManager.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface FileManager extends Remote {

	/**
	 * 从远程服务器获取文件信息
	 * 
	 * @param path
	 * @param fileName
	 * @return
	 * @throws RemoteException
	 */
	public RemoteFileInfo getRemoteFile(String path, String fileName)
			throws RemoteException;

}

RemoteFileInfo.java
import java.io.Serializable;
import java.util.List;

/**
 * 文件实体类
 */
public class RemoteFileInfo implements Serializable{
	private String fileName; 	// 文件名
//	private byte[] content;
	private List content;		// 文件内容 (每1024个字节的内容作为列表的一个元素)
	
	
	public RemoteFileInfo(String fileName, List content) {
		this.fileName = fileName;
		this.content = content;
	}

	
	public List getContent() {
		return content;
	}

	public void setContent(List content) {
		this.content = content;
	}
	

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}
	
}

2. 实现接口,根据RMI规范,接口实现类的名应以“接口文件名+Impl.java”命名。此类不仅要实现远程接口,还要继承UnicastRemoteObject类,声明构造函数(构造函数也要抛出RemoteException异常)
FileManagerImpl.java
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 文件操作实现类
 */
public class FileManagerImpl extends UnicastRemoteObject implements FileManager {
private static final Log log = LogFactory.getLog(FileManagerImpl.class);

	public FileManagerImpl() throws RemoteException {
		super();
	}

	public RemoteFileInfo getRemoteFile(String path, String fileName)
			throws RemoteException {
		try {
			RemoteFileInfo remoteFile;
			List content = new ArrayList();
			File file = new File(path + fileName);
			BufferedInputStream in = new BufferedInputStream(
					new FileInputStream(file));
			
			// 处理大文件时,每次读取1024个字节存到centent对象
			byte[] bufContent = new byte[1024];
			while(in.read(bufContent) !=-1){
				content.add(bufContent);
				bufContent = new byte[1024];
			}
			
			/*
			// 只能用到内容少的文件,遇到大文件会出现内容溢出错误
			byte[] content = new byte[(int)file.length()];
			
			in.read(content);
			*/
			remoteFile = new RemoteFileInfo(fileName,content);
			log.info("Getting ["+fileName+"] is successful");
			
			return remoteFile;
		} catch (IOException e) {
			log.error("Failed to get ["+fileName+"] ...");
			e.printStackTrace();
			return null;
		}
	}

3. 生成Stub类(JDK为5.0或以上可以忽略此步),作此步时要先生成了实现类的class文件.
使用javac命令生成.class文件。(e.g. Unix下:javac -classpath .:./lib/commons-logging.jar:
./lib/log4j-1.2.15.jar package1/package2/FileManagerImpl.java)
 在命令行中运行 rmic –v1.2 FileManagerImpl,若实现类被打包要加上包名(e.g. rmic –v1.2 packageA.packageB.packageC. FileManagerImpl).
 若执行成功则会生成一个FileManagerImpl_Stub.class的类文件.
4. 实现RMI应用布署程序
FileServer.java
import java.io.InputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 布署应用
*/
public class FileServer {
	private static final Log log = LogFactory.getLog(FileServer.class);
	public static final String CONFIG_FILE_PATH = "/conf/config.properties";
	
	/**
	 * 获取配置信息
	 * @return	URL
	 */
	public static Map getURL(){
		try{
			String url, port;
			Map configs = new HashMap();
			Properties prop = new Properties();
			InputStream in = FileServer.class.getResourceAsStream(CONFIG_FILE_PATH);
		
			prop.load(in);
			url = prop.getProperty("server.interface");
			port = prop.getProperty("server.port");
			configs.put("url", url);
			configs.put("port", port);
			
			return configs;
		} catch (IOException e){
			System.out.println("读取配置信息失败!");
			e.printStackTrace();
			return null;
		}
	}
	
	public static void main(String[] args){
		try {
			Map configs = getURL();
			if(configs != null){
				String port = configs.get("port").toString();
				String url = configs.get("url").toString();
				
				// 根据端口号开启一个RMI服务.也可以不指定,默认为1099
				LocateRegistry.createRegistry(Integer.parseInt(port));
				FileManagerImpl fileMng = new FileManagerImpl();
						
				log.info("Binding URL:"+url);
			
				// 注册一个RMI应用
				// e.g. url: //127.0.0.1:20002/FILE_MNG
				Naming.rebind(url, fileMng);
				log.info("Deploy Remote File Server successfully!");
			}
			else{
				log.error("Binding Remote File Server failed...");
			}
			
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}
	
}

5. 为了便于维护,最好将以上程序打到一个JAR包中,在META-INF下的MANIFEST.MF文件中指定运行JAR包需要的Main方法所在的类等信息,像这样:
Manifest-Version: 1.0
Main-Class: package1.package2..FileServer
Class-Path: webapp-server.jar commons-logging.jar log4j-1.2.15.jar
在Unix中用nohup命令在后台启动这个JAR包:
nohup java -jar lib/webapp-server.jar >> $HOME/nohupout/fileserver_log.out &
用ps –ef|grep webapp查看此进程。
如没有进程启动,查看日志文件的错误信息。

客户端1. 客户端需要的文件类有: 远程接口FileManager.java及其相关类,Stub类.
业务类
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import nantian.fxjk.web.util.AccessRemoteServer;

/**
 * 后台文件操作业务类
 */
public class FileClient {
	
	/**
	 * 获取远程服务器上的文件信息
	 * 
	 * @param path		文件路径
	 * @param fileName	文件名
	 * @return
	 */
	public RemoteFileInfo getRemoteFile(String path, String fileName){
		try{
			Map configs = getConfig();
			
			if (configs != null) {
				String url = configs.get("url").toString();
				String defaultPath = configs.get("abs_path").toString();
				
				// 查找一个已布署的远程服务
				// e.g. url: //128.128.96.2:20002/FILE_MNG
				FileManager fileMng = (FileManager) Naming.lookup(url);
	
				RemoteFileInfo file = fileMng.getRemoteFile(
						defaultPath + path, fileName);
				
				return file;
			}
			else{
				System.out.println("读取配置信息失败.");
				return null;
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
			return null;
		} catch (RemoteException e) {
			e.printStackTrace();
			return null;
		} catch (NotBoundException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 将远程服务器上的文件取到本地
	 * 
	 * @param fileInfo
	 * @return
	 */
	public boolean getRemoteFileToLocal(RemoteFileInfo fileInfo,
			String downloadPath) {
		File path = new File(downloadPath);

		if (!path.exists()) {
			path.mkdirs();
		}
		try {
			BufferedOutputStream out = new BufferedOutputStream(
					new FileOutputStream(downloadPath + fileInfo.getFileName()));
			List content = fileInfo.getContent();
			
			for(int i=0; i<content.size(); i++){
				out.write((byte[])content.get(i));
			}
			out.close();

			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 获取访问远程对象的相关配置信息
	 * 
	 * @return		配置信息
	 */
	public Map getConfig() {
		try {
			Map configs = new HashMap();
			Properties prop = new Properties();
			InputStream in = FileClient.class
					.getResourceAsStream(AccessRemoteServer.CONFIG_FILE_PATH);

			prop.load(in);
			configs.put("url", prop.getProperty("server.interface"));
			configs.put("abs_path", prop.getProperty("server.path"));
			configs.put("down_path", prop.getProperty("download.path"));

			return configs;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

2. 编写响应请求的Servlet类
DownloadSysFileAction.java
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 下载后台文件的请求响应类
*/
public class DownloadSysFileAction extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		PrintWriter out;
		OutputStream outStream;
		FileClient fc = new FileClient();
		String fileLocation = request.getParameter("file");
		fileLocation = fileLocation.trim();
		String path = getPath(fileLocation);
		String fileName = getFileName(fileLocation);
		
		
		RemoteFileInfo file = fc.getRemoteFile(path, fileName);
		
		if(file != null){
			List content = file.getContent();
			outStream = response.getOutputStream();
			response.reset();
			response.setContentType("application/x-msdownload"); // 纯下载方式
			response.setHeader("content-disposition", "attachment; filename="+file.getFileName());
			
			for(int i=0; i<content.size(); i++){
				outStream.write((byte[]) content.get(i));
			}
			response.flushBuffer();
			outStream.close();
		}
		else{
			response.setContentType("text/html;charset=UTF-8");
			out = response.getWriter();
			out.println("<script type='text/javascript'>");
			out.println("alert('不存在该文件!'); window.close();");
			out.println("</script>");
			out.close();
			return ;
		}
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request,response);
	}
	// … … … 
}

3. 前台页面提供要下载的文件名和所在路径,再调用这个Servlet就可以下载远程服务器上的文件了

你可能感兴趣的:(java,apache,log4j,应用服务器,unix)