基于C/S的网盘设计(JAVA) - 网盘源码-实现部分功能
由于有其他的工作,网盘做了一部分不得不放手了,
我希望有时间的其他朋友可以继续工作,虽然网络上有很多现成的网盘代码,不过还是希望自己能做一个,并借鉴一些优秀的思想来实现,下面说下实现过程,有些部分需要改进
一、数据库的设计,目前只涉及到用户表,当然还有其他的,你可以根据需要来增加
#用户表
create table m_user(
id int primary key auto_increment,
name varchar(32) not null unique,
password char(32) not null,
`gender` enum('男','女') NOT NULL DEFAULT '男',
phone varchar(20),
email varchar(50) not null,
reg_date char(16) not null,
reg_ip varchar(15) not null,
last_login_date char(16),
last_login_ip varchar(15)
);
二、数据源的设置,我这里使用c3p0数据源,当然你可以使用dbcp或者其他的
配置c3p0-config.xml文件就可以了,网络上有详细的配置项,或者在我源码里面下载,在最后公布下载地址
在这里我写一个简单的JdbcUtil,当然还可以编写一些复杂的操作,工作不允许我继续往下写了,你可以集成一些操作,就像hibernate那样
public class JdbcUtil { /** * 数据库连接管理器 */ // private static Logger log = Logger.getLogger(JdbcUtil.class); /*初始化数据库连接池*/ private static DataSource dataSource = new ComboPooledDataSource(); /*获取数据源*/ public DataSource getDataSource(){ return dataSource; } /*获取连接*/ public static Connection getConnection() throws SQLException{ return dataSource.getConnection(); } /*释放连接*/ public static void free(ResultSet rs,PreparedStatement ps,Connection conn){ if(null != rs){ try { rs.close(); } catch (SQLException e) {} } if(null != ps){ try { ps.close(); } catch (SQLException e) {} } if(null != conn){ try { conn.close(); } catch (SQLException e) {} } } public static void free(PreparedStatement ps,Connection conn){ if(null != ps){ try { ps.close(); } catch (SQLException e) {} } if(null != conn){ try { conn.close(); } catch (SQLException e) {} } } }
三、我这里先说说服务端
1.socket线程池
池的作用想必大家都知道,循环利用资源,我这里的这个池只是简单的池,没有时间再完成一个复杂的工作了
cn.mike.server.ServerThread是一个负责处理用户请求的线程,我们要创建一批这样的线程,并由cn.mike.server.ServerThreadPool管理,代码如下:
public class ServerThreadPool { /** * 服务端线程池 */ private final static Logger log = Logger.getLogger(ServerThreadPool.class); //线程组 public static LinkedList<ServerThread> threadPool = new LinkedList<ServerThread>(); private static int maxPoolSize;//最大连接数 private static int minPoolSize;//最小连接数 private static int initialPoolSize;//初始化连接数 private static int maxIdleTime;//连接的最大空闲时间,单位:秒 private static int acquireIncrement;//在当前连接数耗尽的时候,一次获取的新的连接数 static int maxWaitUserTime;//线程等待用户操作的最大时间,到达最大时间未传送数据,则进行线程释放 public ServerThreadPool(){ initProperties(); initThreadPool(); } /* * 初始化配置 */ public void initProperties(){ System.out.println("正在启动线程池..."); System.out.println("正在加载线程池配置文件..."); Properties pro = new Properties(); HashMap<String, String> propertiesMap = new HashMap<String, String>(); try { pro.load(ServerThreadPool.class.getClassLoader().getResourceAsStream(ServerThreadPoolConfig.PROPS_FILE_RSRC_PATH)); propertiesMap.put(ServerThreadPoolConfig.MAX_POOL_SIZE, pro.getProperty(ServerThreadPoolConfig.MAX_POOL_SIZE)); propertiesMap.put(ServerThreadPoolConfig.MIN_POOL_SIZE, pro.getProperty(ServerThreadPoolConfig.MIN_POOL_SIZE)); propertiesMap.put(ServerThreadPoolConfig.INITIAL_POOL_SIZE, pro.getProperty(ServerThreadPoolConfig.INITIAL_POOL_SIZE)); propertiesMap.put(ServerThreadPoolConfig.MAX_IDLE_TIME, pro.getProperty(ServerThreadPoolConfig.MAX_IDLE_TIME)); propertiesMap.put(ServerThreadPoolConfig.ACQUIRE_INCREMENT, pro.getProperty(ServerThreadPoolConfig.ACQUIRE_INCREMENT)); propertiesMap.put(ServerThreadPoolConfig.MAX_WAIT_USER_TIME, pro.getProperty(ServerThreadPoolConfig.MAX_WAIT_USER_TIME)); if(null != propertiesMap.get(ServerThreadPoolConfig.MAX_POOL_SIZE)){ ServerThreadPool.maxPoolSize = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MAX_POOL_SIZE)); }else{ ServerThreadPool.maxPoolSize = 100; } if(null != propertiesMap.get(ServerThreadPoolConfig.MIN_POOL_SIZE)){ ServerThreadPool.minPoolSize = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MIN_POOL_SIZE)); }else{ ServerThreadPool.minPoolSize = 5; } if(null != propertiesMap.get(ServerThreadPoolConfig.INITIAL_POOL_SIZE)){ ServerThreadPool.initialPoolSize = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.INITIAL_POOL_SIZE)); }else{ ServerThreadPool.initialPoolSize = 5; } if(null != propertiesMap.get(ServerThreadPoolConfig.MAX_IDLE_TIME)){ ServerThreadPool.maxIdleTime = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MAX_IDLE_TIME)); }else{ ServerThreadPool.maxIdleTime = 10; } if(null != propertiesMap.get(ServerThreadPoolConfig.ACQUIRE_INCREMENT)){ ServerThreadPool.acquireIncrement = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.ACQUIRE_INCREMENT)); }else{ ServerThreadPool.acquireIncrement = 1; } if(null != propertiesMap.get(ServerThreadPoolConfig.MAX_WAIT_USER_TIME)){ ServerThreadPool.maxWaitUserTime = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MAX_WAIT_USER_TIME)); }else{ ServerThreadPool.maxWaitUserTime = 60000; } } catch (Exception e) { log.error("线程池配置文件加载出错,请确保文件threadPool.properties存在,并正确配置!"); System.exit(1); } System.out.println("线程池配置加载成功,配置信息如下:"); System.out.println("#################################"); System.out.println("最大连接数:"+ServerThreadPool.maxPoolSize); System.out.println("最小连接数:"+ServerThreadPool.minPoolSize); System.out.println("初始化连接数:"+ServerThreadPool.initialPoolSize); System.out.println("连接的最大空闲时间:"+ServerThreadPool.maxIdleTime+" 秒"); System.out.println("在当前连接数耗尽的时候,一次获取的新的连接数:"+ServerThreadPool.acquireIncrement); System.out.println("线程等待用户操作的最大时间:"+ServerThreadPool.maxWaitUserTime+" 毫秒"); System.out.println("#################################"); } /* * 初始化服务线程 */ public void initThreadPool(){ for(int i=0;i<ServerThreadPool.initialPoolSize;i++){ ServerThread st = new ServerThread(); st.start(); threadPool.add(st); } } /* * 线程池动态调整器 */ public void poolAdjust(){ } }
一些配置规范我把它放在cn.mike.server.ServerThreadPoolConfig里
public class ServerThreadPoolConfig { /* * 线程池配置 */ //配置文件路径 public final static String PROPS_FILE_RSRC_PATH = "threadPool.properties"; //最大连接数 public final static String MAX_POOL_SIZE = "maxPoolSize"; //最小连接数 public final static String MIN_POOL_SIZE = "minPoolSize"; //初始化连接数 public final static String INITIAL_POOL_SIZE= "initialPoolSize"; //连接的最大空闲时间,单位:秒 public final static String MAX_IDLE_TIME = "maxIdleTime"; //在当前连接数耗尽的时候,一次获取的新的连接数 public final static String ACQUIRE_INCREMENT = "acquireIncrement"; //线程等待用户操作的最大时间,到达最大时间未传送数据,则进行线程释放 public final static String MAX_WAIT_USER_TIME = "maxWaitUserTime"; }
threadPool.properties文件用于配置线程池的一些选项,我这里的设置可能不够完整,你可以根据需要增加
还有一个重要问题,这里需要开启一个线程来管理线程池里线程的数量,实现动态调整,这工作我并没完成,希望你能把它完成
cn.mike.server.Server是一个用于接收用户请求的分配器,处理一些初始化工作
public class Server { /** * 25米 网盘 服务端 */ private final static Logger log = Logger.getLogger(Server.class); private int listenPort = 8594;//监听端口 private static ServerSocket ss; static LinkedList<Socket> taskQueue = new LinkedList<Socket>();//任务队列 public static Map<String,Session> sessionMap = new HashMap<String,Session>(); /*初始化线程池*/ ServerThreadPool stp = new ServerThreadPool(); /*数据库连接工具*/ public JdbcUtil jdbcUtil = new JdbcUtil(); private int maxWaitUserTime = ServerThreadPool.maxWaitUserTime;//最大等待操作时间 public static void main(String[] args) { System.out.println("正在启动服务器..."); Server server = new Server(); new TaskHandle().start(); server.init(); } public void init(){ // 初始化数据库连接池 System.out.println("正在初始化数据库连接池..."); try { System.out.println("#################################"); JdbcUtil.getConnection().close(); System.out.println("#################################"); System.out.println("数据库连接池创建成功!"); } catch (SQLException e1) { log.error("数据库连接池创建失败!"); System.exit(1); } /*开启监听服务*/ try { ss = new ServerSocket(listenPort); System.out.println("服务器启动成功,正在监听端口:"+listenPort); while(true){ Socket socket = ss.accept(); socket.setSoTimeout(maxWaitUserTime);//设置最大连接时长 System.out.println("发现客户端连接,IP:"+socket.getRemoteSocketAddress()); process(socket);//转入线程池处理 } } catch (IOException e) { System.out.println("服务器启动失败,请确保端口:"+listenPort+"不被其他程序占用!"); } } /* * 服务线程处理客户端请求 */ public void process(Socket socket){ if(ServerThreadPool.threadPool.size()>0){//如果池中还有服务线程 ServerThreadPool.threadPool.removeFirst().startWork(socket); } else if(taskQueue.size()<1000){//若没有,并且队列长度小于1000,则加入任务队列 taskQueue.add(socket); } else{ try { socket.close(); } catch (IOException e) { log.error("关闭客户端socket失败!"); } } } } /* *开启定时器,处理任务队列,每隔 500 毫秒查看有没有空闲连接 */ class TaskHandle extends Thread{ static LinkedList<Socket> taskQueue = Server.taskQueue; public TaskHandle(){ System.out.println("队列任务处理器开启.."); } public void run() { try { while(true){ Thread.sleep(500); if(taskQueue.size()>0 && ServerThreadPool.threadPool.size()>0){//如果池中还有服务线程,则处理任务队列 ServerThreadPool.threadPool.removeFirst().startWork(Server.taskQueue.removeFirst()); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
可能有些东西读者不是很明白,这需要对socket编程熟悉点,当然我的设计也有些问题,希望读者能提改进意见,有时间就修改
服务端启动如下:
四、下面说说客户端
客户端就是登陆界面和管理网盘界面
1.登陆界面:cn.mike.client.ClientLogin
不是很漂亮,勉强用着吧,当然你可以设计得漂亮点
登陆成功后是这样的:
大概做到这里了,数据的上传下载等没时间实现了,感兴趣的朋友可以继续我的工作
源码我放到CSDN下面:http://download.csdn.net/detail/mzlqh/4514886