练手项目:用openresty + lua + jqurey 制作一个随机发牌网页,openrestyjqurey


项目要求:

制作一个可随机发牌的网页,并:

用openresty里的nginx搭建web server

用lua写后台逻辑,

用redis存储卡牌数据,

用jqurey写一个前端界面。


首先展示下我做出来的成品:

展示

制作的很垃圾,但好歹了解了怎么前端和后端的一些联系。

具体项目的地址


这里简要记录一下制作的过程吧。

第一步:搭建web server服务器

下载Xshell,登录linux服务器,下载openresty-1.11.2.2 ,解压。

    wget https://openresty.org/download/openresty-1.11.2.2.tar.gz

进入解压后的目录,执行

	./configure  --prefix=/usr/local/server

这样的话,openresty就会被安装到/usr/local/server目录下。

(有可能会出现如下报错

./configure:  error: the HTTP rewrite module requires the PCRE library.

只需要安装pcre-devel即解决问题  yum -y install pcre-devel)

然后执行

	make

再执行

	make install

具体可参照:openresty安装详解

安装结束后,打开/usr/local/server/nginx/conf/nginx.conf(具体由安装位置决定)

查看listen监控的端口是不是80,若是,用ifconfig看一下是否开通

查看设置情况:iptables -L -n

开启80端口:iptables -A INPUT -p tcp --dport 80 -j ACCEPT 

执行  ./usr/local/server/nginx/sbin/nginx          (重启是./usr/local/server/nginx/sbin/nginx  -s reload )

打开浏览器,输入服务器ip地址,显示openresty欢迎页面,说明web服务器开启成功!


第二步:新建nginx项目

自己找一个目录存放项目,这里我选择/usr/example

项目目录建立如下:

example

     example.conf     ---该项目的nginx 配置文件

    lua              ---存放我们自己的lua代码

       test.lua

     lualib            ---存放lua依赖库/第三方依赖

      *.lua

      *.so

修改nginx的主配置文件/usr/servers/nginx/conf/nginx.conf

      修改其中部分内容,将项目所在位置包含进主配置文件

#user  nobody;  
worker_processes  2;  
error_log  logs/error.log;  
events {  
    worker_connections  1024;  
}  
http {  
    include       mime.types;  
    default_type  text/html;  
    #lua模块路径,其中”;;”表示默认搜索路径,默认到/usr/servers/nginx下找  
    lua_package_path "/usr/example/lualib/?.lua;;";  #lua 模块  
    lua_package_cpath "/usr/example/lualib/?.so;;";  #c模块  
    include /usr/example/example.conf;          #关键,即包含了你项目所在的位置
}  


接着编写example.conf文件如下

server {  
    listen       80;     #监听端口80
    server_name  _;  
    charset utf-8;
	
    location /{        #首页,包含首页面
       root /usr/example/;
       index index.php index.htm index.html;
    }

    location /deal {    #洗牌请求
	set $dealn 1;     
	set $randseed 1;
        default_type 'text/html';
	lua_code_cache off;
	content_by_lua_file /lishaoxiao/example/lua/deal.lua;    #洗牌请求所在后端文件
    }

    location /remain_card{   #剩余卡牌请求
    	default_type 'text/html';
	lua_code_cache off;
	content_by_lua_file /lishaoxiao/example/lua/remain_card.lua;   #剩余卡牌请求所在后端文件
    }

}  


那么我们nginx部分算配完了,该写后端逻辑了。


第三步:编写lua脚本

我们要思考要做的后端任务,提供哪些接口。

可以知道我们需要提供 发牌接口deal,用来发牌,以及剩余卡牌接口remain_card,用于检测剩余卡牌和初始化网页。

而这里我用redis数据库来简单储存一下数据,所以需要再提供一个数据库mrcard。

总共写3个lua文件,分别为mrcard.lua,remain_card.lua,deal.lua

首先写mrcard.lua,该文件处理了如何与redis数据库配合进行发牌洗牌。

--文件名为mrcard.lua
--用来获取redis中card数据的模块
--定义一个名为mrcard的模块
--请记得先配置文件间的依赖关系,并保证path路径能搜查到你所需要的模块。
--card:是一个集合,指代剩余牌库
--ddealcard:是一个列表,用来获取已发牌,用于网页的初始化
mrcard = {}
--连通redis数据库操作
local function open_redis()
    local redis = require("resty.redis")
    local red = redis:new()
    red:set_timeout(1000)
    local ip = "127.0.0.1"
    local port = 6379
    local ok, err = red:connect(ip, port)
    if not ok then
        ngx.say("connect to redis error : ", err)
        return close_redis(red)
    end    
    return red

end

--关闭redis数据库连接
local function close_redis(red)  
        if not red then  
            return  
        end  
        local ok, err = red:close()  
        if not ok then  
            ngx.say("close redis error : ", err)  
        end  
end  

-- 获取剩余牌堆函数
function mrcard.getrcard()
    local red = open_redis()
    local resp, err = red:smembers("card")  
    if not resp then  
        ngx.say("get msg error : ", err)  
        close_redis(red)  
    end  
   
    if resp == ngx.null then  
        resp = ''  
    end
 
    close_redis(red)
    return resp
end

--获取已经被发过的牌,用于页面初始化
function mrcard.getdealcard()
    local red = open_redis()
    --local resp,err = red:smembers("dealcard")
    local resp,err = red:lrange("ddealcard",0,53)
    if resp == ngx.null then
	resp = ''
    end

    close_redis(red)
    return resp
end


--洗牌操作
--需要重置牌库,同时清除已发牌
function mrcard.shuffle()
	local red = open_redis()
	local res = {}
	for i=1,52
	do
		red:sadd("card",i)
		res[i] = i
	--	red:srem("dealcard",'0'+i)
		red:lpop("ddealcard")
	end
	close_redis(red)
	return res
end



--发牌后的数据库操作:在牌库中剔除,以及给已发牌中添加
function mrcard.delecard(delcard)
    local red = open_redis()
    for i,num in pairs(delcard)
    do
        red:srem("card",'0' + num)
	--red:sadd("dealcard",num)
	red:rpush("ddealcard",num)
    end
    
    close_redis(red)
end

return mrcard

接着写发牌接口, 即deal模块。发牌时我们用随机数方法,并结合前端发来的随机数一起进行随机生成。

--发牌接口,
--根据剩余牌堆和发牌数量发牌
--
--


--retTable:发送表,存储信息,转成json格式后发送给前端
retTable={}

--deal():发牌函数
--参数为剩余牌堆 和 发牌数
function deal(remain_card, num, randseed)
	--lua调用ostime所得到的时间为秒级,可结合前端传来的随机数来产生随机种子
        math.randomseed(tonumber(tostring(os.time()):reverse():sub(1,6))*randseed*randseed)
        local dealnum = num   --发牌数
        local cardnum = #remain_card  --牌堆数,现在为52
        local randnum = 0
        local card = remain_card
        local ans = {}
        while( dealnum ~= 0)
        do
		--每次随机到一个后,从该表中剔除,减少重复
        	randnum = math.random(1,cardnum)
                table.insert(ans, card[randnum])
                table.remove(card,randnum)
                dealnum = dealnum - 1
                cardnum = cardnum - 1
   	end
        return ans
end
        
--输出函数
--现在不做处理,只输出数字
function putcard(res)
        for i,num in ipairs(res)
        do
		retTable[i] = num
        end
end


--接口运行部分


--获取post得到的发牌数dealnum
local rcard = require("mrcard")
ngx.req.read_body()
post_args = ngx.req.get_post_args()
local DealNum = 10
DealNum = post_args["dealn"]
local RandSeed = post_args["randseed"]

--判断发牌数和剩余牌堆数的大小
--shuffleflag决定是否洗牌
local num = 5
num = DealNum + 0
local RemainCard = rcard.getrcard()
retTable["shuffleflag"]="N"
if(num > #RemainCard)
then
	RemainCard = rcard.shuffle()
	retTable["shuffleflag"]="Y"
end



--开始发牌,并存入retTable表
local res = deal(RemainCard,num,RandSeed)
putcard(res)

--在剩余牌库中剔除已经发出的牌
rcard.delecard(res)

--置剩余牌堆数
retTable["Remain_card"] = #RemainCard - num

--用cjson库进行发送
local cjson=require("cjson")
local jsonstr=cjson.encode(retTable)
ngx.say(jsonstr)


最后写剩余卡牌接口

--剩余牌堆接口


mcard = require("mrcard") --调用redis和card的模块

--local RemainCard = mcard.getrcard()
local dealcard = mcard.getdealcard()
local cjson=require("cjson")
local restable={}
restable["remain_num"]= 52-table.getn(dealcard)
for i,num in pairs(dealcard)
do
	restable[i]=num
end

local resstr=cjson.encode(restable)
ngx.say(resstr)

发回前端时都把字符串改为 json格式,利用lua自带的cjson模块。


第四步:编写前端页面

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>发牌程序</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>


<script>
/*
	作者: DrawBreak
	联系QQ: 799581228 
	时间: 2017-5-03
*/
//nowcardn:当前已发的牌数量,用来确定牌的位置
var nowcardn=0;
var number=["A","2","3","4","5","6","7","8","9","10","J","Q","K"];
var strchar=["魏","蜀","吴","群"];

//发牌动画,参数为json和发牌数
var movecard = function(json,dealnum)
{ 
	for(var i = 1;i <= dealnum-0; i++)
	{
		//h1是发出牌的类的标题元素,dealcard
		var $h1=$('<div class="dcard"><div/>');
		var j=json[i];
		//将新建的元素h1增添到dealarea的子元素中
		//该子元素通过寻找最后一个子元素last-child,在lastchild元素后新建该元素
		$(".dealarea").children("div:last-child").after($h1);	
		//此时h1成为最后一个元素

		//js中使用除法要用Math.floor
		var picstr = strchar[Math.floor((j-1)/13)] + number[(j-1)%13];
		$(".dealarea").children("div:last-child").html(picstr);
		
		//css()设置图片,并进行位移
		$(".dealarea").children("div:last-child").css({"background":"url(./images/"+j+".png)","background-size":"100% 100%"}).delay(120*i).animate
		(
			{marginTop:200+180*Math.floor(nowcardn/8)+"px",marginLeft:-130+130*(nowcardn%8) +"px"},100
		);
		
		nowcardn++;		
		var rnum=52-nowcardn;
		$('#remaintext').delay(120*i).text(rnum);	
	}
} 

$(document).ready(function()
{ 
	//网页初始化,先执行一次ajax操作,获取之前已经发的牌
	$.ajax
	({
		type:"POST",
		url:"http://10.225.254.127/remain_card",
		success:function(data)
		{
			var json=$.parseJSON(data);
			var rnum=json.remain_num;
			$('#remaintext').text(rnum);
			nowcardn=0;
			movecard(json,52-rnum);
		}
	});
	//发牌操作
	$("#btn1").click(function()
	{		
	    var dealnum = $("#deal").val();
		
		//数据正确性判断
		if( dealnum < 0 || dealnum >52)
		{
			alert("只有52张牌!发牌数应为0-52!");
			return ;
		}
		else if(!(dealnum>=0&&dealnum<=52))
		{
			alert("请输入数字!范围为0-52");
			return ;
		}
		
		//产生一个随机数,和后端共同结合使用
		var randnum = parseInt(Math.random() * (52) + 1);
	 
		//ajax获取数据库信息
	    $.ajax
		({
			type:"POST",
			url:"http://10.225.254.127/deal",
			data:{dealn:dealnum,randseed:randnum},
			//datatype默认为josn格式
			success:function(data)
			{						
				var json = $.parseJSON(data);
				if(json.shuffleflag == "Y")
				{
					nowcardn=0;
					//清除所有card
					$(".dcard").each(function()
					{
						$(this).animate
						(
							{marginTop:10+"px",marginLeft:200+"px"},300
						);
						//用remove清除时,要用obj对象而不是this。
						var obj=$(this);	
						setTimeout(function()
							{
								obj.remove();
							},200
						);
						
					});
					movecard(json,dealnum);
				}
				else
				{
					//针对传回来的数组进行处理,记住,数组从1开始
					//数字字符串-0  则变为数字
					movecard(json,dealnum);
				}
			}										
		});			
	});		
}) ;
</script>

<style>
    body {
        width: 100%;
        font-family: Tahoma, Verdana, Arial, sans-serif;
		background-image:url(./images/background2.jpg)
    }
	
	.dealarea
	{
		width:1400px;
		margin:10px 200px;
	}
	.dealarea:first-child
	{
		float:none;
	}
	.dcard,.back
	{	
		width:120px;
		height:160px;
		border-radius:0px;
		border:0px solid #333;
		margin: 10px 200px;
		float:left;	
		text-align:center;
		line-height:160px;
		position:absolute;
		color:white;
		font-family:"楷体","楷体_GB2312";
		font-size:20px;
	}	
	.back{
		background-image:url(./images/background.jpg);
		background-size:100% 100%;
		color:#00BFFF;
		font-family:"楷体","楷体_GB2312";  	
	}	
	
</style>


<title>无标题文档</title>


</head>

<body>
	<div class="dealarea">
		<div class="back">
		</div>
	</div>
	
	<div id="div2">
		<h3 id="remain">剩余数量</h3>
		<h3 id="remaintext">text1</h3>
		<p>发牌数量:<input type="text" id="deal" value="1"></p>
		<button id="btn1" type="button">发牌</button>
	</div>
</body>
</html>

自此搭建完成。第一次搭建里,要留意lua模块间的依赖,没弄好的话肯定是没法使用的。

相关内容

    暂无相关文章