练手项目:用openresty + lua + jqurey 制作一个随机发牌网页,openrestyjqurey
练手项目:用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; #关键,即包含了你项目所在的位置
}
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模块间的依赖,没弄好的话肯定是没法使用的。
评论暂时关闭