• 基于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

  • 相关阅读:
    SpringCloud系列——TX-LCN分布式事务管理
    SpringCloud系列——限流、熔断、降级
    SpringBoot系列——Logback日志,输出到文件以及实时输出到web页面
    常用的js、java编码解码方法
    WebSocket数据加密——AES与RSA混合加密
    使用Fiddler重定向App的网络请求
    C# 调用 taskkill命令结束服务进程
    Install .Net Core For CentOS
    cron表达式详解[转]
    WinServer远程部署系统打包批处理文件
  • 原文地址:https://www.cnblogs.com/mikevictor07/p/2648716.html
Copyright © 2020-2023  润新知