基于C/S的網(wǎng)盤設計(Java)
由于有其他的工作,網(wǎng)盤做了一部分不得不放手了,我希望有時間的其他朋友可以繼續(xù)工作,雖然網(wǎng)絡上有很多現(xiàn)成的網(wǎng)盤代碼,不過還是希望自己能做一個,并借鑒一些優(yōu)秀的思想來實現(xiàn),下面說下實現(xiàn)過程,有些部分需要改進
一、數(shù)據(jù)庫的設計,目前只涉及到用戶表,當然還有其他的,你可以根據(jù)需要來增加
用戶表
- 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)
- );
二、數(shù)據(jù)源的設置,我這里使用c3p0數(shù)據(jù)源,當然你可以使用dbcp或者其他的
配置c3p0-config.xml文件就可以了,網(wǎng)絡上有詳細的配置項,或者在我源碼里面下載,在最后公布下載地址
在這里我寫一個簡單的JdbcUtil,當然還可以編寫一些復雜的操作,工作不允許我繼續(xù)往下寫了,你可以集成一些操作,就像hibernate那樣
- public class JdbcUtil {
- /**
- * 數(shù)據(jù)庫連接管理器
- */
- // private static Logger log = Logger.getLogger(JdbcUtil.class);
- /*初始化數(shù)據(jù)庫連接池*/
- private static DataSource dataSource = new ComboPooledDataSource();
- /*獲取數(shù)據(jù)源*/
- 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) {}
- }
- }
- }
#p#
三、我這里先說說服務端
1.socket線程池
池的作用想必大家都知道,循環(huán)利用資源,我這里的這個池只是簡單的池,沒有時間再完成一個復雜的工作了
cn.mike.server.ServerThread是一個負責處理用戶請求的線程,我們要創(chuàng)建一批這樣的線程,并由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;//最大連接數(shù)
- private static int minPoolSize;//最小連接數(shù)
- private static int initialPoolSize;//初始化連接數(shù)
- private static int maxIdleTime;//連接的最大空閑時間,單位:秒
- private static int acquireIncrement;//在當前連接數(shù)耗盡的時候,一次獲取的新的連接數(shù)
- static int maxWaitUserTime;//線程等待用戶操作的最大時間,到達最大時間未傳送數(shù)據(jù),則進行線程釋放
- 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("最大連接數(shù):"+ServerThreadPool.maxPoolSize);
- System.out.println("最小連接數(shù):"+ServerThreadPool.minPoolSize);
- System.out.println("初始化連接數(shù):"+ServerThreadPool.initialPoolSize);
- System.out.println("連接的最大空閑時間:"+ServerThreadPool.maxIdleTime+" 秒");
- System.out.println("在當前連接數(shù)耗盡的時候,一次獲取的新的連接數(shù):"+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);
- }
- }
- /*
- * 線程池動態(tài)調(diào)整器
- */
- public void poolAdjust(){
- }
- }
一些配置規(guī)范我把它放在cn.mike.server.ServerThreadPoolConfig里
- public class ServerThreadPoolConfig {
- /*
- * 線程池配置
- */
- //配置文件路徑
- public final static String PROPS_FILE_RSRC_PATH = "threadPool.properties";
- //最大連接數(shù)
- public final static String MAX_POOL_SIZE = "maxPoolSize";
- //最小連接數(shù)
- public final static String MIN_POOL_SIZE = "minPoolSize";
- //初始化連接數(shù)
- public final static String INITIAL_POOL_SIZE= "initialPoolSize";
- //連接的最大空閑時間,單位:秒
- public final static String MAX_IDLE_TIME = "maxIdleTime";
- //在當前連接數(shù)耗盡的時候,一次獲取的新的連接數(shù)
- public final static String ACQUIRE_INCREMENT = "acquireIncrement";
- //線程等待用戶操作的最大時間,到達最大時間未傳送數(shù)據(jù),則進行線程釋放
- public final static String MAX_WAIT_USER_TIME = "maxWaitUserTime";
- }
threadPool.properties文件用于配置線程池的一些選項,我這里的設置可能不夠完整,你可以根據(jù)需要增加
還有一個重要問題,這里需要開啟一個線程來管理線程池里線程的數(shù)量,實現(xiàn)動態(tài)調(diào)整,這工作我并沒完成,希望你能把它完成
cn.mike.server.Server是一個用于接收用戶請求的分配器,處理一些初始化工作
- public class Server {
- /**
- * 25米 網(wǎng)盤 服務端
- */
- private final static Logger log = Logger.getLogger(Server.class);
- private int listenPort = 8594;//監(jiān)聽端口
- 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();
- /*數(shù)據(jù)庫連接工具*/
- 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(){
- // 初始化數(shù)據(jù)庫連接池
- System.out.println("正在初始化數(shù)據(jù)庫連接池...");
- try {
- System.out.println("#################################");
- JdbcUtil.getConnection().close();
- System.out.println("#################################");
- System.out.println("數(shù)據(jù)庫連接池創(chuàng)建成功!");
- } catch (SQLException e1) {
- log.error("數(shù)據(jù)庫連接池創(chuàng)建失??!");
- System.exit(1);
- }
- /*開啟監(jiān)聽服務*/
- try {
- ss = new ServerSocket(listenPort);
- System.out.println("服務器啟動成功,正在監(jiān)聽端口:"+listenPort);
- while(true){
- Socket socket = ss.accept();
- socket.setSoTimeout(maxWaitUserTime);//設置最大連接時長
- System.out.println("發(fā)現(xiàn)客戶端連接,IP:"+socket.getRemoteSocketAddress());
- process(socket);//轉(zhuǎn)入線程池處理
- }
- } 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("關(guān)閉客戶端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編程熟悉點,當然我的設計也有些問題,希望讀者能提改進意見,有時間就修改
服務端啟動如下:
四、下面說說客戶端
客戶端就是登陸界面和管理網(wǎng)盤界面
1.登陸界面:cn.mike.client.ClientLogin
不是很漂亮,勉強用著吧,當然你可以設計得漂亮點
登陸成功后是這樣的:
大概做到這里了,數(shù)據(jù)的上傳下載等沒時間實現(xiàn)了,感興趣的朋友可以繼續(xù)我的工作
原文鏈接:http://www.cnblogs.com/mikevictor07/archive/2012/08/21/2648716.html
【編輯推薦】