您的位置:首页 > 编程语言 > Java开发

基于C/S的网盘设计(JAVA)

2012-08-21 14:49 323 查看
一、数据库的设计,目前只涉及到用户表,当然还有其他的,你可以根据需要来增加

#用户表

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



不是很漂亮,勉强用着吧,当然你可以设计得漂亮点

登陆成功后是这样的:



大概做到这里了,数据的上传下载等没时间实现了,感兴趣的朋友可以继续我的工作
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息