用 simpleHttpServer + layui 制作一个简单的web文件管理系统

Mr_MAO 2023-9-18 2569

最近学了一下前端框架layui,感觉layui作者风格和aardio作者风格一样,都是”简洁+实用“。下面是练习的作品,没有什么技术含量,也没写权限管理和日志(大家有兴趣有时间可以完善),界面看上去还算顺眼,颜值主要靠layui(真是省了大把html+css代码)长脸了,代码写的不好,希望大家多提意见。

import win.ui;
/*DSG{{*/
winform = win.form(text="简易WEB文件服务器";right=570;bottom=183;border="dialog frame";max=false)
winform.add(
btnOpenFolder={cls="button";text="...";left=491;top=46;right=531;bottom=78;z=5};
btnStart={cls="button";text="启动服务器";left=44;top=100;right=193;bottom=142;font=LOGFONT(h=-13);z=1};
edit={cls="edit";left=107;top=46;right=483;bottom=77;dl=1;dr=1;dt=1;edge=1;z=2};
static1={cls="static";text="共享目录:";left=35;top=46;right=107;bottom=78;center=1;font=LOGFONT(h=-13);transparent=1;z=3};
weblink={cls="syslink";text="网站未运行";left=214;top=115;right=518;bottom=139;dr=1;dt=1;transparent=1;z=4}
)
/*}}*/

import gdip.bitmap;
import win.image;  
import fsys.stream;	//上面三个库主要用于保存favicon.ico
import fsys;
import fsys.info; 	//用来获取文件图标
import fsys.dlg.dir;
import  inet.http;

//配置网页及网页标题等信息
winform.root = io._exedir;
winform.title = "在线文件管理系统";
winform.admin = "Mr_MAO";
winform.html = inet.http.get("https://aardio.online/attach-download-145.htm");//加载附件"web.html"

//配置服务器
import wsock.tcp.simpleHttpServer;
namespace wsock.tcp.simpleHttpServer{
    startIp = "0.0.0.0";
    //startPort = 8080;	
    threadGlobal = { winform = ..winform };
    documentRoot = ..winform.root;
}

//获取文件图标,生成缩略图
winform.getfileIcon = function(path){ 
	var sfi = fsys.info.get(path, 0x100/*_SHGFI_ICON*/ | 0x4000/*_SHGFI_SYSICONINDEX*/);
	var bmp = ..gdip.bitmap(sfi.hIcon,1/*_IMAGE_ICON*/);	 
	if(sfi.hIcon)::DestroyIcon(sfi.hIcon);	
	if(bmp) return bmp.saveToBuffer(".png");
}

winform.btnStart.oncommand = function(id,event){
  if(string.trim(owner.text)=="启动服务器"){
	if(winform.edit.text=="") winform.edit.text = winform.root;
	//检查 favicon.ico
	if(not io.exist(winform.root + "favicon.ico")){
	    var hIcon = win.image.extractIcon(io._exepath,,false)  
	    var bmp = gdip.bitmap(hIcon,1);
	    var stream = fsys.stream()
	    bmp.saveToStream(stream, "*.png")
	    string.save(winform.root + "/favicon.ico", stream.readAll() )	
	    ::DestroyIcon(hIcon) 
	}	
	//检查 logo.png
	if(not io.exist(winform.root +"logo.png")){
	    var hIcon = win.image.extractIcon(io._exepath,,false)  
	    var bmp = gdip.bitmap(hIcon,1);
	    bmp.save(winform.root +"logo.png")
	    ::DestroyIcon(hIcon)
	}	
	
	//检查 回收站文件夹
	var recyclefolder = winform.root + "回收站"
        if(!io.exist(recyclefolder)){
	    fsys.createDir(recyclefolder)
	    fsys.attrib(recyclefolder,,2/*_FILE_ATTRIBUTE_HIDDEN*/)
        }    

	//启动simpleHttpServer服务器
	url = wsock.tcp.simpleHttpServer.startUrl(
	    function(response,request,session){ 
		import fsys;
		import web.json;
		import thread.table; //线程表
			
        	//主页   
        	if(request.path == "/main.aardio"){
        	    var path = request.query("folderpath")
        	    if(!path || path=="/"){ //主页请求
        	    	html = string.loadcode(winform.html, 
        	    	//利用模板语法初始化其它一些网站参数
        	    	{title=winform.title;admin=winform.admin;nav="<a><cite>根目录</cite></a>";currDir="/";table_url="/"})
            	}else {  //面包屑请求
            	    //将url参数分解为数组,并组装为breadcrumb路径
            	    path=string.trimright(path,'/') 
            	    var tab  = string.split(path,'/')
            	    var temp = ""
            	    var breadcrumb_str=""
            	    for(k,v in tab){
			temp += v +"/"
			if(k<#tab){
			    if(v==""){
    			        v="根目录";
				breadcrumb_str += "<a href='/'>" + v + "</a>";
			    }else{
				breadcrumb_str += "<a href='/?folderpath=" + temp + "'>" + v + "</a>";
			    }
			}else {
			    breadcrumb_str += "<a><cite>"+ v + "</cite></a>";
			}
		    }
            	    html = string.loadcode(winform.html, 
            		{title=winform.title;admin=winform.admin;nav=breadcrumb_str;currDir=path;table_url=path})
            	}	
            	response.contentType = "text/html";
            	response.write(html)
            	return;
        	}

        	//返回指定目录内的文件列表
        	if(request.path == "/getfolder"){     
        	    var path = request.query("folderpath")
        	    var serverPath = io.joinpath(request.documentRoot, path)

        	    //检索对应的本地目录
                if( fsys.isDir(serverPath) ){
        			var templist = {}
        			fsys.enum( serverPath, "*.*",
                		function(dir,filename,fullpath,findData){ 
                		    if(findData.dwFileAttributes & 2/*_FILE_ATTRIBUTE_HIDDEN*/) return; //不显示隐藏目录&文件
                    		if(filename){	//文件
                            	var size = math.size64(findData.nFileSizeLow,findData.nFileSizeHigh).format()
                            	var mdftime =  tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");//utc时间
                    			var webPath = string.right(fullpath,-#request.documentRoot)
                    			webPath = string.replace(webPath,"@\","/")
                            	table.push(templist,
                            		{["name"]=filename,["size"]=size,["time"]=mdftime;["path"]=webPath;["type"]=0}) //设定type=0为文件
                    		}else{	//目录	
                            	var mdftime =  tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");	
                    			var webPath = string.right(fullpath,-#request.documentRoot)
                    			webPath = string.replace(webPath,"@\","/")
                    			table.push(templist,
                    				{["name"]=dir,["size"]="/",["time"]=mdftime;["path"]=webPath;["type"]=1}) //设定type=1为目录
                    		}
                		} 
                		,0/*不包括子目录*/
            		);
            		var retlist = {}
            		if(#templist>0){
        				retlist = table.mix({},{"code"=0; "msg"="success";  "count"=#templist; "data"=templist} )
        			}else{
        				retlist = {"code"=1; "msg"="该目录为空";}  //空目录
        			}
        			//返回json
        			var json = web.json.stringify(retlist,true)
        			response.contentType = "text/json"
        			response.write(json)
                }else{
                	response.contentType = "text/json"
                	var retJson = '{ "code": 1, "msg": "错误,找不到你指定的目录"}'
                	response.write(retJson)
                }
                return;
        	}	
        	 
			//返回缩略图
			if(string.startWith(request.path,"/thumbnail",true) ){    
        	    var path = string.right(request.path,-#"/thumbnail/")
        	    var serverPath = io.joinpath(request.documentRoot, path)
        	    
				if(io.exist(serverPath)){
					if(fsys.isDir(serverPath)){
						if(!thread.table("iconlist")["folder"]){
							thread.table("iconlist")["folder"] = winform.getfileIcon(io._exedir)
						}
						response.contentType = "image/png";
        	    		response.write( thread.table("iconlist")["folder"] ) //发送文件夹图标	
					}else{
						var ext = fsys.getExtensionName(serverPath) //exe (没有.)
						if(ext=='exe'){
							response.contentType = "image/png";
        	    			response.write( winform.getfileIcon(serverPath) )
						}else{
							//在iconlist中找
							if(!thread.table("iconlist")["."+ ext]){
								thread.table("iconlist")["."+ ext] = winform.getfileIcon(serverPath)
							}
							response.contentType = "image/png";
        	    			response.write( thread.table("iconlist")["."+ ext] ) //发送文件夹图标		
						}	
					}
        	   		
        	    }else{
        	        //返回一个默认的图片
        	    }
        	    return;
			}	
      		
        	//返回搜索结果(全站搜索,较慢)
        	if(request.path == "/search"){
        	    var keyword = request.query("keywords")
        	    if(keyword){
        	        var templist = {}
        	        fsys.enum( request.documentRoot, "*.*", 
						function(dir,filename,fullpath,findData){ 
							if(findData.dwFileAttributes & 2/*_FILE_ATTRIBUTE_HIDDEN*/) return; //不搜索隐藏文件
							if(filename){ 
           						if( string.find(filename,"@"++keyword) ){
           	    					var size = math.size64(findData.nFileSizeLow,findData.nFileSizeHigh).format()
                            		var mdftime =  tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");
                    				var webPath = string.right(fullpath,-#request.documentRoot)
                    				webPath = string.replace(webPath,"@\","/")
                            		table.push(templist,
                            			{["name"]=filename,["size"]=size,["time"]=mdftime;["path"]=webPath;["type"]=0})
           						}     	
							}
							else{
           						if(string.find(dir,"@"++keyword)){
           	    					var mdftime =  tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");	
                    				var webPath = string.right(fullpath,-#request.documentRoot)
                    				webPath = string.replace(webPath,"@\","/")
                    				table.push(templist,
                    					{["name"]=dir,["size"]="/",["time"]=mdftime;["path"]=webPath;["type"]=1}) //设定type=1为目录
           						}    
							}
						} ,true
					);
					var retlist = {}
            		if(#templist>0){
        				retlist = table.mix({},{"code"=0; "msg"="success";  "count"=#templist; "data"=templist} )
        			}else{
        				retlist = {"code"=2; "msg"="没有找到包含关键字的文件或目录";}  //空目录
        			}
        			var json = web.json.stringify(retlist,true)
        			response.contentType = "text/json"
        			response.write(json)
        			return;
        	    }    
        	}
        	
        	//响应客户端-新建文件夹
        	if(request.path == "/createfolder"){      	    
        		var path = request.post["fatherdir"]
        		var newname = request.post["foldername"]
        		var serverPath = io.joinpath(request.documentRoot, path)

        		if(io.exist(serverPath)){
        		    if(io.exist(io.joinpath(serverPath,newname))) {
        		        response.errorStatus(417, "已存在同名文件夹!")
        				return;
        		    } else{
        		        if( fsys.createDir(io.joinpath(serverPath,newname)) ){
        		    		response.contentType = "text/json"
        					response.write('{"success":true}')
        					return;
        		        }
        		    }   
        		}    
        		response.errorStatus(404, "目录路径不正确")
        		return;
        	}        	
        	  
        	//响应客户端-改名
        	if(request.path == "/rename"){      	    
        		var path = request.post["path"]
        		var newname = request.post["newname"]
        		var serverPath = io.joinpath(request.documentRoot, path)
        		var newpath = fsys.getParentDir(serverPath) + newname

        		if(io.exist(serverPath)){
        		    if(fsys.rename(serverPath,newpath)){
        		    	response.contentType = "text/json"
        				response.write('{"success":true}')
        				return;
        		    }
        		}    
        		response.errorStatus(404, "File not found!")
        		return;
        	}
 
 			//响应客户端-删除
         	if(request.path == "/delete"){
        		var path = request.post["path"]
        		var serverPath = io.joinpath(request.documentRoot, path)
        		
				var recyclefolder = request.documentRoot + "回收站"
        		
        		if(fsys.isDir(serverPath)){//如果要删除的是文件夹 (设为隐藏属性即可)
        			fsys.attrib(serverPath,,2/*_FILE_ATTRIBUTE_HIDDEN*/)
        			fsys.rename(serverPath,serverPath+"-已删除")
        			response.contentType = "text/json"
        			response.write('{"success":true}')	
        			return;
        		}else {//如果要删除的是文件(移到回收站)
        			if(io.exist(serverPath)){ //文件要真实存在
        				var newdir = fsys.getParentDir( recyclefolder + io.joinpath(path) )
        				if(!io.exist(newdir)) fsys.createDir(newdir)
        				if(fsys.move(serverPath,recyclefolder + io.joinpath(path),0x614/*_FOF_NO_UI*/)){
        					response.contentType = "text/json"
        					response.write('{"success":true}')
        					return;
        				}
        			}
        		}
        		response.errorStatus(404, "未找到指定的文件")
        		return;
        	}    
        				
			//响应客户端-文件下载  
        	if(request.path == "/download/main.aardio"){
        	    var filePath = request.query("filepath")
        	    var serverPath = io.joinpath(request.documentRoot, filePath)
        	    
        	    if(io.exist(serverPath)){
        	        var file = io.open(serverPath,"rb");
        	    	response.contentType = "application/octet-stream"; 
                	response.headers["Content-Disposition"] = "attachment; filename="+ fsys.getFileName(serverPath); 
                	response.headers["Content-Length"] = file.size();

                  	var buffer = raw.buffer(1024 *100);
                  	while(var readsize = file.readBuffer(buffer)){
                    	response.writeBuffer(buffer,readsize)
                  	}
                  	file.close()
        	    }else {
        			response.errorStatus(404, "File not found!")
        	    }
        	    return;   
        	} 
        	
        	//响应客户端-文件上传
 			if(request.path == "/updatefile"){
 				var fileData = request.postFileData();  //获取上传的文件
            	if(fileData){
                	var filename = fileData["file"].filename
 					var path = fileData["dirpath"].value()   //取layui上传文件的data附加数据
 					var serverfolder = io.joinpath(request.documentRoot, path)
 					//保存文件到指定位置
                	fileData["file"].save(serverfolder + "\" + filename);  

                	//layui-upload组件要求上传成功后,必须返回的json
                	response.contentType = "text/json"
                	var retJson = '{ "code": 0, "msg": "' ++ filename ++ '"}'
                	response.write(retJson)
                	return; 
 				}
 				response.contentType = "text/json"
                response.write('{ "code": 1, "msg": "未知错误"}')
 				return;	
 			}
        	 	
        	//响应其他格式的文件请求
        	//response.headers["Access-Control-Allow-Origin"] = "*" //允许跨域(如在线打开office文件)
        	response.loadcode( request.path );
    	}
	);  
	
	winform.edit.disabled = true
	winform.btnOpenFolder.disabled = true
	winform.btnStart.text = "停止服务器";
	winform.weblink.text = `网站已运行 (主页: <a href="` ++ url ++ `">` ++ url ++ "</a> )"

	}else{
		//停止服务器 
		//(如需反复重启,需要修改wsock.tcp.wsock.tcp.simpleHttpServer源码第806行
		//if(serverMain) serverMain.stop();
		//为:if(serverMain) serverMain.stop(); serverMain=null;
		//)
		wsock.tcp.simpleHttpServer.stopUrl()

		winform.edit.disabled = false
		winform.btnOpenFolder.disabled = false
		winform.weblink.text = "网站未运行"
		winform.btnStart.text = "启动服务器";
	}
}

//在浏览器打开网页
winform.weblink.onHyperlinkClick = function(nmSysLink,url,id){
    thread.invoke(
        function(url){
            import process;
            process.execute(url);
        },url
    );
}

//设置共享文件夹
winform.btnOpenFolder.oncommand = function(id,event){
	var folderPath = fsys.dlg.dir()
	if(folderPath){
		if(string.endWith(folderPath,"\")==false) folderPath+= "\"
		winform.edit.text = folderPath;
		winform.root = folderPath;
		//设置为网站根目录
		wsock.tcp.simpleHttpServer.documentRoot = folderPath ;
	}
}

winform.show();
win.loopMessage();


上传的附件:
最新回复 (9)
  • Viewer8122 2023-9-18
    0 2
    谢谢分享~!
  • lcj21 2023-9-19
    0 3
    这个不错,有关layui的,学习一下,感谢分享!
  • tanzh 2023-9-19
    0 4
    不错不错
  • firmlyjin 2023-9-27
    0 5
    真不错
  • aika107 2023-9-27
    0 6
    给你点赞!
  • snai99 11月前
    0 7
    太好了,值得学习!
  • loveboyzmj 10月前
    0 8
    学习学习
  • niheibie 9月前
    0 9
    这个不错
  • 小光芒 9月前
    0 10
    想知道 权限控制怎么写
返回