【轮子狂魔】抛弃IIS,打造个性的Web Server - WebAPI/Lua/MVC(附带源码)

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03


引言

此篇是《【轮子狂魔】抛弃IIS,向天借个HttpListener - 基础篇(附带源码)》的续篇,也可以说是提高篇,如果你对HttpListener不甚了解的话,建议先看下基础篇。

这次玩的东西有点多了,大致分为如下几个方向:

1.支持静态页面

2.Ur映射l执行方法

3.Url映射执行Lua脚本

4.模仿MVC中的C

这些东西有什么用?

支持静态页面:这个纯属玩具吧,只是基础篇作为引子的一个简单示例而已。

Url映射执行方法:类似Web API,可以提供一些基于Http协议的交互方式。

Url映射执行Lua脚本:与上面一样,不同的是,在某些场景下更合适,比如业务频繁变动、频繁发布。Lua脚本我就不细说了,不清楚的可以百度一下,是个很好玩的东西。

模仿MVC中的C:这个实例只是想说基于HttpListener我们可以做很多事情,如果你对ASP.NET、MVC很熟悉,你可以做个整整的Web Server出来,甚至做个Web框架都可以。

那么除了这些还可以做什么?

其实太多了,比如反向代理、负载均衡、黑名单等等,你都可以做。如果你有兴趣可以跟帖讨论 ^_^

改造HttpServer支持横向扩展

抽离出一个接口:HttpImplanter

1 interface HttpImplanter
2     {
3         void Start();
4         void Stop();
5         void MakeHttpPrefix(HttpListener server);
6         ReturnCode ProcessRequest(HttpListenerContext context);
7         byte[] CreateReturnResult(HttpListenerContext context, ReturnCode result);
8     }

改造HttpServer的一些执行细节

  1 /// <summary>
  2     /// 可接收Http请求的服务器
  3     /// </summary>
  4     class HttpServer
  5     {
  6         Thread _httpListenThread;
  7
  8         /// <summary>
  9         /// HttpServer是否已经启动
 10         /// </summary>
 11         volatile bool _isStarted = false;
 12
 13         /// <summary>
 14         /// 线程是否已经结束
 15         /// </summary>
 16         volatile bool _terminated = false;
 17         volatile bool _ready = false;
 18         volatile bool _isRuning = false;
 19         HttpImplanter _httpImplanter;
 20
 21         public void Start(HttpImplanter httpImplanter)
 22         {
 23             if (!HttpListener.IsSupported)
 24             {
 25                 Logger.Exit("不支持HttpListener!");
 26             }
 27
 28             if (_isStarted)
 29             {
 30                 return;
 31             }
 32             _isStarted = true;
 33             _ready = false;
 34             _httpImplanter = httpImplanter;
 35
 36             RunHttpServerThread();
 37
 38             while (!_ready) ;
 39         }
 40
 41         private void RunHttpServerThread()
 42         {
 43             _httpListenThread = new Thread(new ThreadStart(() =>
 44             {
 45                 HttpListener server = new HttpListener();
 46                 try
 47                 {
 48                     _httpImplanter.MakeHttpPrefix(server);
 49                     server.Start();
 50                 }
 51                 catch (Exception ex)
 52                 {
 53                     Logger.Exit("无法启动服务器监听,请检查网络环境。");
 54                 }
 55
 56                 _httpImplanter.Start();
 57
 58                 IAsyncResult result = null;
 59                 while (!_terminated)
 60                 {
 61                     while (result == null || result.IsCompleted)
 62                     {
 63                         result = server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server);
 64                     }
 65                     _ready = true;
 66                     Thread.Sleep(10);
 67                 }
 68
 69                 server.Stop();
 70                 server.Abort();
 71                 server.Close();
 72                 _httpImplanter.Stop();
 73             }
 74             ));
 75
 76             _httpListenThread.IsBackground = true;
 77             _httpListenThread.Start();
 78         }
 79
 80         private void ProcessHttpRequest(IAsyncResult iaServer)
 81         {
 82             HttpListener server = iaServer.AsyncState as HttpListener;
 83             HttpListenerContext context = null;
 84             try
 85             {
 86                 context = server.EndGetContext(iaServer);
 87                 Logger.Info("接收请求" + context.Request.Url.ToString());
 88                 //判断上一个操作未完成,即返回服务器正忙,并开启一个新的异步监听
 89                 if (_isRuning)
 90                 {
 91                     Logger.Info("正在处理请求,已忽略请求" + context.Request.Url.ToString());
 92                     RetutnResponse(context, _httpImplanter.CreateReturnResult(context, new ReturnCode((int)CommandResult.ServerIsBusy, EnumHelper.GetEnumDescription(CommandResult.ServerIsBusy))));
 93                     server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server);
 94                     return;
 95                 }
 96
 97                 _isRuning = true;
 98                 server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server);
 99             }
100             catch
101             {
102                 Logger.Warning("服务器已关闭!");
103                 return;
104             }
105
106             string scriptName = new UrlHelper(context.Request.Url).ScriptName;
107             byte[] resultBytes = null;
108             if (scriptName.ToLower().EndsWith(".html")||scriptName == "favicon.ico")
109             {
110                 string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", scriptName);
111                 if (File.Exists(filePath))
112                 {
113                     resultBytes = File.ReadAllBytes(filePath);
114                 }
115                 else
116                 {
117                     resultBytes = _httpImplanter.CreateReturnResult(context, new ReturnCode((int)CommandResult.FileNotExists, EnumHelper.GetEnumDescription(CommandResult.FileNotExists)));
118                 }
119             }
120             else
121             {
122                 ReturnCode result = _httpImplanter.ProcessRequest(context);
123                 resultBytes = _httpImplanter.CreateReturnResult(context, result);
124             }
125             RetutnResponse(context, resultBytes);
126             _isRuning = false;
127         }
128
129         private static void RetutnResponse(HttpListenerContext context, byte[] resultBytes)
130         {
131             context.Response.ContentLength64 = resultBytes.Length;
132             System.IO.Stream output = context.Response.OutputStream;
133             try
134             {
135                 output.Write(resultBytes, 0, resultBytes.Length);
136                 output.Close();
137             }
138             catch
139             {
140                 Logger.Warning("客户端已经关闭!");
141             }
142         }
143
144         public void Stop()
145         {
146             if (!_isStarted)
147             {
148                 return;
149             }
150
151             _terminated = true;
152             _httpListenThread.Join();
153
154             _isStarted = false;
155         }
156
157     }

Url映射执行方法

1.继承HttpImplanter

2.增加监听前缀,用于过滤Url

3.创建返回结果

3.1 解析Url

3.2 定位访问的类

3.3 执行Url所表示的方法

 1 public class MethodHttpServer : HttpImplanter
 2     {
 3         #region HttpImplanter 成员
 4
 5         public void Start()
 6         {
 7             //nothing to do
 8         }
 9
10         public void Stop()
11         {
12             //nothing to do
13         }
14
15         public void MakeHttpPrefix(System.Net.HttpListener server)
16         {
17             server.Prefixes.Clear();
18             server.Prefixes.Add("http://localhost:8081/");
19             Logger.Info("MethodHttpServer添加监听前缀:http://localhost:8081/");
20         }
21
22         public ReturnCode ProcessRequest(System.Net.HttpListenerContext context)
23         {
24             return new ReturnCode((int)CommandResult.Success, EnumHelper.GetEnumDescription(CommandResult.Success));
25         }
26
27         public byte[] CreateReturnResult(System.Net.HttpListenerContext context, ReturnCode result)
28         {
29             string responseString = string.Empty;
30             UrlHelper urlHelper = new UrlHelper(context.Request.Url);
31             var type = Type.GetType("HttpListenerDemo.Test." + urlHelper.ScriptName);
32             if (type != null)
33             {
34                 object obj = Activator.CreateInstance(type);
35                 responseString = obj.GetType().GetMethod(urlHelper.Parameters["method"]).Invoke(obj, new object[] { urlHelper.Parameters["param"] }) as string;
36             }
37
38             return System.Text.Encoding.UTF8.GetBytes(responseString);
39         }
40
41         #endregion
42     }

测试方法

1 public class TestMethod
2     {
3         public string Test(string msg)
4         {
5             return "TestMethod:" + msg;
6         }
7     }

Url映射执行Lua脚本
  使用Lua前要填坑

首先需要注意的是使用Lua有个坑,我使用的是Lua51.dll,而这个是 .net 2.0版本,而我的程序是 4.0。且这个类库是32位,而我的系统是64位。所以遇到了2个问题。

1.需要修改app.config,增加startup节点,让程序运行时以.net 2.0来加载lua51和LuaInterface这两个程序集。

 1 <startup useLegacyV2RuntimeActivationPolicy="true">
 2     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
 3     <runtime>
 4       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 5         <dependentAssembly>
 6           <assemblyIdentity name="Lua51" publicKeyToken="32ab4ba45e0a69a1" culture="neutral"/>
 7           <codeBase version="v2.0.50727" href="Lua51.dll"/>
 8         </dependentAssembly>
 9         <dependentAssembly>
10           <assemblyIdentity name="LuaInterface" publicKeyToken="32ab4ba45e0a69a1" culture="neutral"/>
11           <codeBase version="v2.0.50727" href="LuaInterface.dll"/>
12         </dependentAssembly>
13       </assemblyBinding>
14     </runtime>
15   </startup>

2.设置项目属性->生成->目标平台-> x86

此时,坑已经填完,开始正式撸代码了。

  实现调用Lua和Url与Lua之间的映射

LuaApiRegister:这个类用于注册Lua虚拟机,告诉Lua虚拟机如果寻找提供给Lua使用的API。

 1     public class LuaApiRegister
 2     {
 3         private Lua _luaVM = null;
 4
 5         public LuaApiRegister(object luaAPIClass)
 6         {
 7             _luaVM = new Lua();//初始化Lua虚拟机
 8             BindClassToLua(luaAPIClass);
 9         }
10
11         private void BindClassToLua(object luaAPIClass)
12         {
13             foreach (MethodInfo mInfo in luaAPIClass.GetType().GetMethods())
14             {
15                 foreach (Attribute attr in Attribute.GetCustomAttributes(mInfo, false))
16                 {
17                     if (!attr.ToString().StartsWith("System.") && !attr.ToString().StartsWith("__"))
18                     {
19                         _luaVM.RegisterFunction((attr as LuaFunction).getFuncName(), luaAPIClass, mInfo);
20                     }
21                 }
22             }
23         }
24
25         public void ExecuteFile(string luaFileName)
26         {
27             Logger.Info("开始执行脚本:" + luaFileName);
28             _luaVM.DoFile(luaFileName);
29         }
30
31         public void ExecuteString(string luaCommand)
32         {
33             try
34             {
35                 _luaVM.DoString(luaCommand);
36             }
37             catch (Exception e)
38             {
39                 Console.WriteLine("执行lua脚本指令:" + e.ToString());
40             }
41         }
42     }
43
44     public class LuaFunction : Attribute
45     {
46         private String FunctionName;
47
48         public LuaFunction(String strFuncName)
49         {
50             FunctionName = strFuncName;
51         }
52
53         public String getFuncName()
54         {
55             return FunctionName;
56         }
57     }

LuaScriptEngineer:这个类将会映射Url解析后的指令如何执行Lua脚本。其中包括定位Lua文件、设置变量、执行脚本和回收资源等。

  1     public class LuaScriptEngineer
  2     {
  3         public string _scriptRoot;
  4         private string _throwMessage = "";
  5         private ReturnCode _returnCode = null;
  6
  7         public void ExecuteScript(string scriptName, NameValueCollection parameters)
  8         {
  9             if (!File.Exists(Path.Combine(_scriptRoot, scriptName + ".lua")))
 10             {
 11                 throw new FileNotFoundException();
 12             }
 13
 14             LuaApiRegister luaHelper = new LuaApiRegister(new TestLuaApiInterface());
 15
 16             InitLuaGlobalParameter(luaHelper, parameters);
 17
 18             ExecuteFile(luaHelper, Path.Combine(_scriptRoot, scriptName + ".lua"));
 19
 20         }
 21
 22         private void InitLuaGlobalParameter(LuaApiRegister luaHelper, NameValueCollection parameters)
 23         {
 24             foreach (var item in parameters.AllKeys)
 25             {
 26                 luaHelper.ExecuteString("a_" + item.Trim() + " = \"" + parameters[item].Replace("\\", "\\\\") + "\";");
 27             }
 28         }
 29
 30         private void ExecuteFile(LuaApiRegister luaHelper, string luaFileName)
 31         {
 32             try
 33             {
 34                 _throwMessage = "";
 35                 _returnCode = null;
 36                 luaHelper.ExecuteFile(luaFileName);
 37             }
 38             catch (ReturnCode returnCode)
 39             {
 40                 _returnCode = returnCode;
 41             }
 42             catch (Exception ex)
 43             {
 44                 _throwMessage = ex.Message;
 45             }
 46
 47             if (_returnCode != null)
 48             {
 49                 throw _returnCode;
 50             }
 51             else if (string.IsNullOrEmpty(_throwMessage))
 52             {
 53                 Logger.Info("脚本执行完毕:" + luaFileName);
 54             }
 55             else if (!string.IsNullOrEmpty(_throwMessage))
 56             {
 57                 Logger.Error(_throwMessage);
 58                 throw new Exception(_throwMessage);
 59             }
 60
 61         }
 62
 63         public void Start()
 64         {
 65             _scriptRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Script");
 66
 67             Logger.Info("脚本路径-" + _scriptRoot);
 68             if (!Directory.Exists(_scriptRoot))
 69             {
 70                 Logger.Error("脚本根路径不存在!");
 71             }
 72
 73             if (File.Exists(_scriptRoot + "Startup.lua"))
 74             {
 75                 Logger.Info("开始执行初始化脚本!");
 76                 try
 77                 {
 78                     ExecuteScript("Startup", new NameValueCollection());
 79                 }
 80                 catch
 81                 {
 82                     Logger.Error("启动初始化脚本失败!");
 83                 }
 84             }
 85         }
 86
 87         public void Stop()
 88         {
 89             try
 90             {
 91                 Logger.Info("开始执行回收资源脚本!");
 92                 ExecuteScript("Cleanup", new NameValueCollection());//清空所调用的资源
 93             }
 94             catch
 95             {
 96                 Logger.Warning("回收资源过程出错");
 97             }
 98         }
 99
100     }

LuaHttpServer:这个类做了一些简单的Url校验和调用LuaScriptEnginner。

 1     class LuaHttpServer : HttpImplanter
 2     {
 3         LuaScriptEngineer _luaScriptEngineer = new LuaScriptEngineer();
 4
 5         #region HttpImplanter 成员
 6
 7         public void Start()
 8         {
 9             _luaScriptEngineer.Start();
10         }
11
12         public void Stop()
13         {
14             _luaScriptEngineer.Stop();
15         }
16
17         public void MakeHttpPrefix(System.Net.HttpListener server)
18         {
19             server.Prefixes.Clear();
20             server.Prefixes.Add("http://localhost:8082/");
21             Logger.Info("LuaHttpServer添加监听前缀:http://localhost:8082/");
22         }
23
24         public ReturnCode ProcessRequest(System.Net.HttpListenerContext context)
25         {
26             UrlHelper urlHelper = new UrlHelper(context.Request.Url);
27             CommandResult result = urlHelper.ParseResult;
28             if (urlHelper.ParseResult == CommandResult.Success)
29             {
30                 try
31                 {
32                     _luaScriptEngineer.ExecuteScript(urlHelper.ScriptName, urlHelper.Parameters);
33                     return new ReturnCode((int)CommandResult.Success, EnumHelper.GetEnumDescription(CommandResult.Success));
34                 }
35                 catch (FileNotFoundException fileNotFoundException)
36                 {
37                     return new ReturnCode((int)CommandResult.NoExistsMethod, EnumHelper.GetEnumDescription(CommandResult.NoExistsMethod));
38                 }
39                 catch (ReturnCode returnCode)
40                 {
41                     return returnCode;
42                 }
43                 catch (Exception ex)
44                 {
45                     return new ReturnCode((int)CommandResult.ExcuteFunctionFailed, EnumHelper.GetEnumDescription(CommandResult.ExcuteFunctionFailed));
46                 }
47             }
48             return new ReturnCode((int)result, EnumHelper.GetEnumDescription(result));
49         }
50
51         public byte[] CreateReturnResult(System.Net.HttpListenerContext context, ReturnCode result)
52         {
53             string responseString = string.Format("code={0}&msg={1}&request={2}",
54                 result.Code,
55                 result.Message,
56                 context.Request.Url.ToString()
57                 );
58
59             return System.Text.Encoding.UTF8.GetBytes(responseString);
60         }
61
62         #endregion
63     }

TestLuaApiInterface:提供给Lua可以调用的接口。这里主要是因为C#本身比Lua的可操作性要高。固定的一些功能还是要转回C#来做,Lua只做一些业务组合。

1     public class TestLuaApiInterface
2     {
3         [LuaFunction("Test")]
4         public void Test(string msg)
5         {
6             Logger.Info("TestLuaApiInterface:" + msg);
7         }
8     }

Test.lua:这只是个测试脚本,很简单,只执行了一下Test方法,注意这里的参数param前面有 a_ ,是因为区别外部参数与Lua内部参数的一种手段,并非一定要这样。这个a_也是在LuaApiScripEngineer里自动添加的。

Test(a_param);

模仿MVC中的C

其实也不只是C,有一点点Route的东西,因为这里需要解析Url定位Controller。并且使用的是 vNext 的方式,类名以Controller结尾即可,不用继承任何类。

1.创建一个Route

1     public class TestMVCRoute
2     {
3         public List<string> RegisterRoutes()
4         {
5             return new List<string>() { "{controller}/{action}" };
6         }
7     }

2.创建一个Controller

1     public class TestMVCController
2     {
3         public string Test()
4         {
5             return "TestMVCController";
6         }
7     }

3.扩展一个 MVCHttpServer

需要注意的是,Start方法中处理了Route(偷懒所以只取FirstOrDefault),只是检索出controller和action的位置而已。

CreateReturnResult方法则是真正的映射逻辑。

 1     class MVCHttpServer : HttpImplanter
 2     {
 3         string _route = null;
 4         int _controllerIndex = -1;
 5         int _actionIndex = -1;
 6
 7         #region HttpImplanter 成员
 8
 9         public void Start()
10         {
11             _route = new TestMVCRoute().RegisterRoutes().FirstOrDefault();
12
13             var routes = _route.Split(‘/‘);
14             for (int i = 0; i < routes.Length; i++)
15             {
16                 if (routes[i] == "{controller}")
17                 {
18                     _controllerIndex = i;
19                 }
20                 else if (routes[i] == "{action}")
21                 {
22                     _actionIndex = i;
23                 }
24             }
25         }
26
27         public void Stop()
28         {
29             //nothing to do
30         }
31
32         public void MakeHttpPrefix(System.Net.HttpListener server)
33         {
34             server.Prefixes.Clear();
35             server.Prefixes.Add("http://localhost:8083/");
36             Logger.Info("MVCHttpServer添加监听前缀:http://localhost:8083/");
37         }
38
39         public ReturnCode ProcessRequest(System.Net.HttpListenerContext context)
40         {
41             return new ReturnCode((int)CommandResult.Success, EnumHelper.GetEnumDescription(CommandResult.Success));
42         }
43
44         public byte[] CreateReturnResult(System.Net.HttpListenerContext context, ReturnCode result)
45         {
46             string responseString = string.Empty;
47             var splitedPath = context.Request.Url.AbsolutePath.Split(new char[] { ‘/‘ }, StringSplitOptions.RemoveEmptyEntries);
48             var controllerName = splitedPath[_controllerIndex] + "Controller";
49             var actionName = splitedPath[_actionIndex];
50
51             var type = Type.GetType("HttpListenerDemo.Test." + controllerName);
52             if (type != null)
53             {
54                 object obj = Activator.CreateInstance(type);
55                 responseString = obj.GetType().GetMethod(actionName).Invoke(obj, null) as string;
56             }
57
58             return System.Text.Encoding.UTF8.GetBytes(responseString);
59         }
60
61         #endregion
62     }

我有一个想法

由于自己一直从事C/S方面的工作,所以我想做个Web项目,可以应用到各种技术,并且是最新的,这期间肯定会遇到重重阻碍,但这并不能影响我前进的步伐。

目前计划使用到的技术包括并不仅限于 ASP.NET MVC 6、SignalR、Web API 3.0、Boostrap、jQuery、Redis。

当然其中一定会有一些创新或者好玩的东西出现。

如果你想加入或者你对此感兴趣,欢迎联系我。

最后,又到了大家最喜爱的公布源码环节 ^_^

http://git.oschina.net/doddgu/WebServerDemo

参考页面:http://qingqingquege.cnblogs.com/p/5933752.html

时间: 2024-10-23 21:42:58

【轮子狂魔】抛弃IIS,打造个性的Web Server - WebAPI/Lua/MVC(附带源码)的相关文章

MVC中使用SignalR打造酷炫实用的即时通讯功能附源码

前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时走的太急,忘记把代码拿出来.想想这已经是大半年前的事情了,时间过了这么久,在当时最新的SignalR2.0.1到现在已经变成了2.2.昨天晚上特地熬了个夜,重新又把它写出来做了一个小小的Demo.当然我只是大自然的搬运工,这个SignalR即时通讯功能里面有一些前端的类库不是我自己写的.我只是改吧改吧~~在此鸣谢 @贤心,是他的几条库才使得我的这个功能如此酷炫.

10个web前端jQuery开发者必备的源码组件

1.Conditioniz – 探测浏览器并条件加载 JavaScript 和 CSS Conditioniz 是一个快速.轻量级(3KB)的 JavaScript 工具,用于探测浏览器和分辨率并条件加载 JavaScript 和 CSS 文件.Conditioniz 从它的 jQuery 前身重建,现在速度要快50%.结合类名添加和 Conditionizr 集成的脚本和样式加载功能,允许你为不同的浏览器指定想加载的脚本和样式.浏览器嗅探通常被认为是不可靠的,Conditionizr 的建立就

Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]

前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作之后一直忙,也就没时间顾虑这个问题了. 说到底还是自己懒了,没花时间来研究. 今天看了tomcat的部分源码 了解了这个url-pattern的机制.  下面让我一一道来. tomcat的大致结构就不说了, 毕竟自己也不是特别熟悉. 有兴趣的同学请自行查看相关资料. 等有时间了我会来补充这部分的知识的. 想要了解url-pattern的大致配置必须了解

Spring MVC 4 RESTFul Web Services CRUD例子(带源码)【这才是restful,超经典】

[本系列其他教程正在陆续翻译中,点击分类:spring 4 mvc 进行查看.源码下载地址在文章末尾.] [翻译 by 明明如月 QQ 605283073] 原文地址:http://websystique.com/springmvc/spring-mvc-4-restful-web-services-crud-example-resttemplate/ 上一篇: Spring 4 MVC @RestController 注解实现REST Service 下一篇:Spring MVC 4 文件上传

Cobbler 全自动化安装、简介、Web界面管理【附送源码包】

Cobbler简介 Cobbler这个英文翻译过来的意思是补鞋匠,为什么会是补鞋匠的意思,很简单,因为它简单得连补鞋匠都能学会安装系统. Cobbler通过将部署系统所涉及的所有服务集中在一起,来提供一个全自动批量快速建立Linux系统的网络安装环境. 在学习Cobbler之前可以看看PXE无人值守安装系统. Cobbler特点: ·Cobbler支持多种Linux操作系统得快速部署,对PXE.DHCP.HTTP.TFTP.Kiskstart.YUM仓库.电源等进行统一管理 ·Cobbler提供

基于WEB的小型酒店管理系统,源码下载

大家好,我是全微毕设团队的创始人,本团队擅长JAVA(SSM,SSH,SPRINGBOOT).PYTHON.PHP.C#.安卓等多项技术. 今天将为大家分析一个小型酒店管理系统(当前酒店管理系统已经得到了充足的发展和完善,一些大的酒店购买了功能强大.数据量处理快速.客户行为研究的软件,借此来提升酒店的核心竞争力.但是对于一些中小规模的酒店而言,昂贵的系统花费.专人的维护是不现实的,也是非常不灵活的.一款简单.灵活.经济适用的中小型酒店管理系统的开发非常具有市场前景. 本文针对上面提到的问题,基于

酷毙了!python用37行代码打造属于自己的音乐播放器,附源码

想不想手动打造一款专属于你的播放器,同时练练Python编程? 如果想,那就立即行动吧! 所需库pygametkintermutagen 至于它们的使用,可以浏览一下文档,如果你想做更功能强大的播放器,那必须好好看看哦! 设计思路作为版本0,我们并不想做太复杂的项目.只需实现以下几个功能: 将某个目录下的mp3文件名在listbox中显示 显示当前播放的歌曲名 播放上一首歌曲 播放下一首歌曲 停止播放 获取目录下的mp3文件直接上代码! def directorychooser():direct

10款web前端基于Jquery的动画源码

1.使用 CSS3 动感的图片标题动画效果 在网站中,有很多地方会需要在图片上显示图片标题.使用 CSS3 过渡和变换可以实现动感的鼠标悬停显示效果.没有使用 JavaScript,所以只能在支持 CSS3 动画的现代浏览器中才能正常工作.您可以查看网页的源代码,了解动画是如何工作的. 在线演示 源码下载 2.简单的轻量级的 jQuery 仪表板插件 sDashboard 是一个轻量的仪表板 jQuery 插件,转换一个对象数组到仪表板.数组中的每个对象将被呈现为一个仪表板组件,可以通过左右拖

web大文件上传断点续传源码

总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块),但这不是我们现在说的重点,我们要做的事是保证在网络中断后1G的文件已上传的那部分在下次网络连接时不必再重传.所以我们本地在上传的时候,要将大文件进行分片,比如分成1024*1024B,即将大文件分成1M的片进行上传,服务器在接收后,再将这些片合并成原始文件,这就是分片的基本原理.断点续