svn通信项目文件收发

这是一个SVN通信的项目,涵盖服务器与客户端的文件收发流程,目的是为了保证文件能够正确的在网络中进行传输,客户端上传的文件可以保存在服务器中,同时客户端可以下载服务器之前有用户上传过的所有文件,并以列表的形式展示在客户端。由于当时没有学习数据库,因此在当时处理的时候,文件都是存储在指定文件夹中的,当然这里我们的关注点还是文件在网络中的传输,剩下的可以随着我们学习的深入再进行改进。我认为这种的学习方式非常好,因为学习是一个循序渐进的过程,平时对知识点的学习就应该像单元测试一样,了解我们的关注点并针对进行学习,最后伴随着学习的深入在全部综合运用。

这个项目中我负责的是客户端的文件发送下载与刷新列表,客户端项目的具体分包情况如下:

这里我的业务逻辑的处理基本上都是在这个net.control包下的,我处理的方式是把基本的监听都和界面分开来,单独拿出来处理业务,给他们相应的要传输的参数。

package net.control;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

public class MyClient {
	// 声明对象输入输出流

	private ObjectOutputStream oos;
	private ObjectInputStream ois;

	public MyClient() {
		setClient();
	}

	public void setClient() {
		try {

			Socket client = new Socket("localhost", 9090);
			System.out.println("客户端启动成功");
			OutputStream ous = client.getOutputStream();
			InputStream ins = client.getInputStream();
			// 包装数据流
			oos = new ObjectOutputStream(ous);
			ois = new ObjectInputStream(ins);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public ObjectOutputStream getOos() {
		return oos;
	}

	public ObjectInputStream getOis() {
		return ois;
	}

}

这个类是用来创建socket以及对象输入输出流的,这里之前处理的时候以这种比较严谨的方式封装的,后来学了一些设计模式后发现这里还是用单例模式比较好,这样能保证每次只能够拿到一个对应且相同的socket的对象,ObjectOutputStream对象和ObjectInputStream对象。

package net.control;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.JOptionPane;

import net.view.ChooseFrame;
import net.view.LogonPanel;
import net.view.RegistFrame;

public class LogonListener implements ActionListener {
	private String str;

	private String command;
	private String username;
	private String password;
	public MyClient mc;
	public LogonPanel lp;

	public LogonListener(LogonPanel lp) {
		this.lp = lp;
	}

	public void actionPerformed(ActionEvent e) {

		// 点击登陆按钮并且登陆成功时执行的界面切换
		if (e.getSource() == lp.logon_button) {
			mc = new MyClient();

			username = lp.account_text.getText();
			password = lp.password_text.getText();
			command = "logon";
			// 发消息
			try {
				mc.getOos().writeUTF(command);
				mc.getOos().flush();
				mc.getOos().writeUTF(username);
				mc.getOos().flush();
				mc.getOos().writeUTF(password);
				mc.getOos().flush();
				str = mc.getOis().readUTF();
				if (str.equals("logon ok")) {
					lp.lf.dispose();
					ChooseFrame cf = new ChooseFrame(lp.lf);
				} else if (str.equals("logon fail")) {
					JOptionPane.showMessageDialog(null, "用户名或密码不正确");
				}
			} catch (IOException e1) {
				e1.printStackTrace();
			}

		}
		if (e.getSource() == lp.regist_button) {
			RegistFrame rf = new RegistFrame(lp);
			command = "注册";
		}
	}
}

这个类是对登陆的监听,这里把监听器不写作匿名内部类而单独写出来用来实现ActionListener接口,把要传入的参数传进来的目的是进行相应的页面跳转处理。

package net.control;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.JOptionPane;

import net.view.RegistPanel;

public class RegistListener implements ActionListener {

	public RegistPanel rp;

	public RegistListener(RegistPanel rp) {
		this.rp = rp;
	}

	public void actionPerformed(ActionEvent e) {
		System.out.println(rp.rf.lp.ll.mc.getOos());
		//
		ObjectOutputStream oos = rp.rf.lp.ll.mc.getOos();

		ObjectInputStream ois = rp.rf.lp.ll.mc.getOis();

		if (e.getSource() == rp.jbt) {
			String str = "regist";
			try {
				oos.writeUTF(str);
				oos.flush();
				String s = ois.readUTF();

				if (s.equals("regist ok")) {
					rp.rf.dispose();
				} else if (s.equals("regist fail")) {
					JOptionPane.showMessageDialog(null, "注册失败,您输入的用户名已经存在或密码为空");
				}

			} catch (IOException e1) {
				e1.printStackTrace();
			}

		}
	}

}


这个类是对注册的监听

package net.control;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Date;
import java.util.Vector;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import net.common.Tool;
import net.dao.Data;
import net.view.SendPanel;

public class SendListener implements ActionListener {

	public File file;
	private String str;
	// 添加该监听的面板
	public SendPanel sp;

	// 构造方法
	public SendListener(SendPanel sp) {
		this.sp = sp;
	}

	public void actionPerformed(ActionEvent e) {
		// 点击选择文件按钮时的操作
		if (e.getSource() == sp.jbt) {
			JFileChooser jfc = new JFileChooser();
			jfc.showOpenDialog(null);
			file = jfc.getSelectedFile();
			sp.pathfield.setText(file.getAbsolutePath().toString());
			System.out.println("内容为" + sp.pathfield.getText());
			System.out.println(file.getName());

			// 文件队列中加入该文件
			Data.filelist.add(file);

			long length = file.length();

			Vector<String> vec = new Vector();
			vec.add(file.getName());
			vec.add(String.valueOf(file.length()) + "字节");
			vec.add(new Date().toString());
			vec.add("等待上传");
			sp.data.add(vec);
		}

		// 点击提交按钮时的操作
		if (e.getSource() == sp.submit) {
			try {
				ObjectOutputStream oos = sp.sff.cf.lf.lp.ll.mc.getOos();

				oos.writeUTF("send file");
				oos.flush();

				// 遍历要上传的文件列表
				oos.writeObject(Data.filelist);
				oos.flush();

				for (int i = 0; i < Data.filelist.size(); i++) {
					File myfile = Data.filelist.get(i);
					Tool.sendFile(myfile, oos);
				}
				JOptionPane.showMessageDialog(null, "文件传输完毕");

			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}

	}
}


这个是对客户端传输文件的监听,如果成功或者失败都会有相应的弹窗提示传输的结果。

package net.control;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Vector;

import javax.swing.JOptionPane;

import net.common.Tool;
import net.dao.Data;
import net.view.DownloadPanel;

public class DownloadListener implements ActionListener {
	public ArrayList<String> namelist = new ArrayList<String>();
	public Vector<String> vec;
	public DownloadPanel dp;
	private String str;
	public int count;

	public DownloadListener(DownloadPanel dp) {
		this.dp = dp;
	}

	public void actionPerformed(ActionEvent e) {
		ObjectOutputStream oos = dp.sff.cf.lf.lp.ll.mc.getOos();
		ObjectInputStream ois = dp.sff.cf.lf.lp.ll.mc.getOis();

		// 点击刷新列表按钮时:
		if (e.getSource() == dp.update) {
			str = "update jtable";
			try {
				dp.data.clear();
				oos.writeUTF(str);
				oos.flush();

				// 刷新时先清除列表,再把现存队列中的数据写进去
				Data.downlist = (ArrayList<File>) ois.readObject();

				for (int i = 0; i < Data.downlist.size(); i++) {
					File file = Data.downlist.get(i);
					vec = new Vector<String>();
					vec.add(file.getName());
					vec.add(String.valueOf(file.length()) + "字节");
					vec.add(new Date().toString());
					vec.add("等待下载");
					dp.data.add(vec);
				}

			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}

		// 点击下载按钮时
		if (e.getSource().equals(dp.download)) {
			str = "download file";
			try {
				oos.writeUTF(str);
				oos.flush();
				// 在选择队列添加选择的行
				Tool.getSelectedList(dp);
				// 把选择的队列发过去
				oos.writeObject(Data.selectlist);
				oos.flush();
				for (int i = 0; i < Data.selectlist.size(); i++) {
					FileOutputStream fos = new FileOutputStream("D:/文件下载/" + Data.selectlist.get(i).getName());
					Tool.getFile(ois, fos);
				}
				JOptionPane.showMessageDialog(null, "下载完毕");

			} catch (IOException e1) {
				e1.printStackTrace();
			}

		}

		// 点击同步服务器按钮时
		if (e.getSource() == dp.localout) {
			str = "local out";
			try {
				oos.writeUTF(str);
				oos.flush();
				for (int i = 0; i < Data.downlist.size(); i++) {
					FileOutputStream fos = new FileOutputStream("D:/文件下载/" + Data.downlist.get(i).getName());
					Tool.getFile(ois, fos);
					System.out.println("客户端同步完毕");
				}
				JOptionPane.showMessageDialog(null, "同步服务器完毕");

			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}

}


这是对从服务器下载文件的监听,这里包括选择单个或几个一起下载和同步服务器(即把服务器所有文件都下载下来)

package net.control;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Vector;

import net.dao.Data;
import net.view.ChoosePanel;
import net.view.SendFileFrame;

public class ChooseListener implements ActionListener {
	public ChoosePanel cp;
	public Vector<String> vec;

	public ChooseListener(ChoosePanel cp) {
		this.cp = cp;
	}

	public void actionPerformed(ActionEvent e) {
		// 点击上传文件按钮直接切换界面
		if (e.getSource() == cp.update_button) {
			// 界面切换
			cp.cf.dispose();
			SendFileFrame sff = new SendFileFrame(cp.cf);
			sff.pp.getCl().first(sff.pp);
		}

		// 点击下载文件按钮时切换页面并且在页面加载服务器的文件列表
		if (e.getSource() == cp.download_button) {
			// 界面切换
			cp.cf.dispose();
			SendFileFrame sff = new SendFileFrame(cp.cf);
			sff.pp.getCl().last(sff.pp);

			String str = "update jtable";
			// 获取对象流
			ObjectOutputStream oos = cp.cf.lf.lp.ll.mc.getOos();
			ObjectInputStream ois = cp.cf.lf.lp.ll.mc.getOis();

			try {
				oos.writeUTF(str);
				oos.flush();
				// 对象输入流写入文件
				Data.downlist = (ArrayList<File>) ois.readObject();
				for (int i = 0; i < Data.downlist.size(); i++) {
					File file = Data.downlist.get(i);
					vec = new Vector<String>();
					vec.add(file.getName());
					vec.add(String.valueOf(file.length()) + "字节");
					vec.add(new Date().toString());
					vec.add("等待下载");
					sff.pp.dlp.data.add(vec);
				}

			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
	}

}


这里是用来刷新展示列表的。那么基本的业务流程就是这些,剩下的工具类和数据类保存着一些 要经常用到的方法或属性,都定义为static的

package net.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import net.dao.Data;
import net.view.DownloadPanel;

public class Tool {

	public static void getSelectedList(DownloadPanel dp) {
		// 获取选择的文件内容
		int[] array = dp.table.getSelectedRows();
		for (int i = 0; i < array.length; i++) {
			for (int j = 0; j < Data.downlist.size(); j++) {
				String filename = (String) dp.table.getValueAt(array[i], 0);
				if (filename.equals(Data.downlist.get(j).getName())) {
					Data.selectlist.add(Data.downlist.get(j));
				}
			}
		}
	}

	// 发送文件的方法
	public static void sendFile(File file, ObjectOutputStream oos) {
		try {
			FileInputStream fis = new FileInputStream(file);
			// 统计写入次数作为协议传输
			long length = file.length() / 2048;
			int last = (int) file.length() % 2048;
			// 写入协议
			oos.writeLong(length);
			oos.flush();
			oos.writeInt(last);
			oos.flush();
			System.out.println("发送length:" + length + "   " + last);
			byte[] bytes = new byte[2048];
			while (length > 0) {
				fis.read(bytes);
				oos.write(bytes);
				oos.flush();
				length--;
			}
			if (last > 0) {
				bytes = new byte[last];
				fis.read(bytes);
				oos.write(bytes);
				oos.flush();
			}
			fis.close();
			System.out.println("文件写入完毕");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	// 接收文件方法
	public static void getFile(ObjectInputStream ois, FileOutputStream fos) {

		try {
			// 传输过程
			long length = ois.readLong();
			int last = ois.readInt();

			byte[] bytes = new byte[2048];
			while (length > 0) {
				ois.readFully(bytes);
				fos.write(bytes);
				fos.flush();
				length--;
			}
			if (last > 0) {
				bytes = new byte[last];
				ois.readFully(bytes);
				fos.write(bytes);
				fos.flush();
			}
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

package net.dao;

import java.io.File;
import java.util.ArrayList;

/**
 * Data类用来存各种要传的队列
 * 
 * @author panhao
 *
 */
public class Data {
	// 队列用于保存要上传的文件
	public static ArrayList<File> filelist = new ArrayList<File>();
	// 队列用于保存要下载的文件
	public static ArrayList<File> downlist = new ArrayList<File>();
	// 队列保存选择要下载的文件
	public static ArrayList<File> selectlist = new ArrayList<File>();
}


总体上客户端大概的业务和数据代码就这么多,界面的话,swing写的比较丑,代码有太多就不列出来了。




接下来,服务器这边主要就这两个类的代码,由于这块主要不是我弄,罗列一下代码大家看一下吧:

package net.control;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import net.dao.DataBase;

public class MyServer extends Thread {
	private int port;
	private ServerSocket server;
	private Vector<Vector<String>> data;

	public MyServer(int port, Vector<Vector<String>> data) {
		this.port = port;
		this.data = data;
	}

	public ServerSocket getServer() {
		return server;
	}

	public void run() {
		try {
			// 1.创建服务器对象
			server = new ServerSocket(9090);

			System.out.println("服务器创建好了");
			// 2.获取服务
			while (true) {
				Socket socket;
				socket = server.accept();
				System.out.println("客户端连接上了" + socket.getRemoteSocketAddress());
				ServerThread st = new ServerThread(socket, data);
				st.start();
				DataBase.list.add(st);
			}

		} catch (IOException e) {
			while (DataBase.list.size() > 0) {
				ServerThread st = DataBase.list.remove(0);
				try {
					st.socket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}

		}
	}

}

package net.control;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.Vector;

import net.common.Tool;
import net.dao.Data;
import net.dao.DataBase;

public class ServerThread extends Thread {
	private String s;
	public Socket socket;
	public InputStream ins;
	public OutputStream ous;
	private Vector<Vector<String>> data;

	static {
		File file = new File("F:/文件传输数据");
		File files[] = file.listFiles();
		// 当文件夹存在时
		for (int i = 0; i < files.length; i++) {
			Data.downlist.add(files[i]);
		}
	}

	public ServerThread(Socket socket, Vector<Vector<String>> data) {
		this.socket = socket;
		this.data = data;
	}

	public void run() {
		try {

			// 通过连接对象获取输入输出流
			OutputStream ous = socket.getOutputStream();
			InputStream ins = socket.getInputStream();
			ObjectOutputStream oos = new ObjectOutputStream(ous);
			ObjectInputStream ois = new ObjectInputStream(ins);

			String command = ois.readUTF();
			String userName = ois.readUTF();
			String passWord = ois.readUTF();

			System.out.println("获取命令为" + command);
			System.out.println("用户名为" + userName);
			System.out.println("密码为" + passWord);

			// 当接受到消息时
			if (command.equals("logon")) {
				// 当登陆成功时
				if (Tool.isUserExit(userName, passWord, DataBase.hmp)) {
					System.out.println("用户名密码相同");
					// 在服务器界面上添加用户名登录时间等信息
					Vector<String> vec = new Vector();
					vec.add(userName);
					vec.add(socket.getRemoteSocketAddress().toString());
					vec.add(new Date().toString());
					data.add(vec);

					String str = "logon ok";
					oos.writeUTF(str);
					oos.flush();

					// 执行完登陆消息以后等待客户端指令
					while (true) {
						s = ois.readUTF();

						// 获取到上传命令时
						if (s.equals("send file")) {
							try {
								Data.filelist = (ArrayList<File>) ois.readObject();

								for (int i = 0; i < Data.filelist.size(); i++) {
									Data.downlist.add(Data.filelist.get(i));
								}
							} catch (ClassNotFoundException e) {
								e.printStackTrace();
							}
							for (int i = 0; i < Data.filelist.size(); i++) {
								// System.out.println("保存文件:" +
								// Data.filelist.get(i).getName());
								FileOutputStream fos = new FileOutputStream(
										"F:/文件传输数据/" + Data.filelist.get(i).getName());
								Tool.getFile(ois, fos);
							}

						}

						// 点击更新按钮时
						if (s.equals("update jtable")) {
							oos.writeObject(Data.downlist);
							oos.flush();

						}

						// 点击下载文件按钮时
						if (s.equals("download file")) {
							try {
								Data.selectlist = (ArrayList<File>) ois.readObject();
								for (int i = 0; i < Data.selectlist.size(); i++) {
									File file = Data.selectlist.get(i);
									Tool.sendFile(file, oos);
								}

							} catch (ClassNotFoundException e) {
								e.printStackTrace();
							}
						}
						// 同步服务器时

						if (s.equals("local out")) {
							for (int i = 0; i < Data.downlist.size(); i++) {
								File files = Data.downlist.get(i);
								FileInputStream fis = new FileInputStream(files);
								Tool.sendFile(files, oos);
							}

						}
					}

				} else {
					String str = "logon fail";
					oos.writeUTF(str);
					oos.flush();
				}

			}

			// 注册时的操作
			if (s.equals("regist")) {
				if (Tool.isRegist(userName, passWord, DataBase.hmp)) {
					oos.writeUTF("regist fail");
					oos.flush();
				} else {
					DataBase.hmp.put(userName, passWord);
					oos.writeUTF("regist ok");
					oos.flush();
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

package net.dao;

import java.io.File;
import java.util.ArrayList;

public class Data {

	// 队列用于选择要上传的文件
	public static ArrayList<File> filelist = new ArrayList<File>();
	// 队列保存下载的文件
	public static ArrayList<File> downlist = new ArrayList<File>();
	// 队列保存要下载的文件
	public static ArrayList<File> selectlist = new ArrayList<File>();
}

package net.dao;

import java.util.ArrayList;
import java.util.HashMap;

import net.control.ServerThread;

public class DataBase {
	public static HashMap<String, String> hmp = new HashMap();
	public static ArrayList<ServerThread> list = new ArrayList();

	// 静态块,预存账号密码,模拟数据库
	static {
		for (int i = 0; i < 10; i++) {
			hmp.put("a" + i, "a" + i);
		}
	}
}

package net.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;

public class Tool {
	// 判断用户名是否已经存在并且密码是否为空
	public static boolean isRegist(String userName, String passWord, HashMap<String, String> hmp) {
		if (hmp.containsKey(userName)) {
			return false;
		} else {
			if (passWord != null) {
				return true;
			}
			return false;
		}
	}

	// 判断哈希map中用户名密码是否符合
	public static boolean isUserExit(String username, String passWord, HashMap<String, String> hmp) {
		if (hmp.containsKey(username)) {
			if (hmp.containsValue(passWord)) {
				return true;
			}
		}

		return false;
	}

	// 发送文件方法
	public static void sendFile(File file, ObjectOutputStream oos) {
		try {
			FileInputStream fis = new FileInputStream(file);
			// 统计写入次数作为协议传输
			long length = file.length() / 2048;
			int last = (int) file.length() % 2048;
			// 写入协议
			oos.writeLong(length);
			oos.flush();
			oos.writeInt(last);
			oos.flush();
			byte[] bytes = new byte[2048];
			while (length > 0) {
				fis.read(bytes);
				oos.write(bytes);
				oos.flush();
				length--;
			}
			if (last > 0) {
				bytes = new byte[last];
				fis.read(bytes);
				oos.write(bytes);
				oos.flush();
			}
			fis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	// 接收文件方法
	public static void getFile(ObjectInputStream ois, FileOutputStream fos) {

		try {
			// 传输过程
			long length = ois.readLong();
			int last = ois.readInt();
			System.out.println(length + "   " + last);
			byte[] bytes = new byte[2048];
			while (length > 0) {
				ois.readFully(bytes);
				fos.write(bytes);
				fos.flush();
				length--;
			}
			if (last > 0) {
				bytes = new byte[last];
				ois.readFully(bytes);
				fos.write(bytes);
				fos.flush();
			}
			fos.close();

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}


最后实际运行的效果展示给大家看一下吧:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值