最近太忙了,忙着做iOS项目,还有家里又有孕妇要照顾,本来早就答应糖果写这篇分享的,今天抽空来跟大家分享下做这个项目当中遇到坑,怎么解决的,很一些还有疑问的地方,请各位or同仁多多指教,长话短说就开始这次实践的分
我会以下几点来做比较完善分享
- 项目整体需求以及框架选择
- 开发过程中遇到的坑,以及怎么填坑
- 实践中还有觉得不足的有待完善的点
项目地址在:https://github.com/SandWind/trccms
- 项目整体需求
这个项目做为给朋友做一个健身馆宣传首页,它有一个首页介绍和四个专题介绍,首页包含一个广告banner和四个健身项目专题链接,每个专题页面四个内容的展示,分别是活动照片,场馆图文介绍,教练图文介绍,每周课程简介。
这里项目就开始有2个部分一个部分是供非管理用户参观的展示页面,与管理员的后台页面。
首先,设计并构建好前端静态模板页面 第二,根据页面展示内容构建数据库模型。这里可以参考项目工程文件中model文件中model.sql文件。 第三,安装openresty后,我开始选择框架这个时候,之前我选择vanilla,这个框架没有处理好session,但是整体上看,它是一个完整的mvc的框架,然后参考了https://github.com/bungle/awesome-resty链接中的东西最后选择了lor,相比之前它小巧灵活,安装简捷。简直就是so easy,这是还是要感谢饭总等各位辛劳。 第四,框架搭建完了,这个时候首先要熟悉这个框架数据流程,这里不得不推荐看看 http://doc.lua.ren/ms2008_lor_framework_route.html 要熟悉整个框架的数据路由。按照数据路由,我开始写出如下路由:
router.lua 文件中
local userRouter = require("app.routes.user")
local HomePageRouter= require("app.routes.homepage")
local judoPageRouter= require("app.routes.judo")
local yogoPageRouter= require("app.routes.yoga")
local freepowerPageRouter = require("app.routes.freepower")
local AerabicPageRouter= require("app.routes.aerabic")
local AdminPageRouter = require("app.routes.admin")
local AuthRouter = require("app.routes.auth")
local uploadRouter = require("app.routes.upload")
local AdtopicRouter = require("app.routes.adtopic")
local CoverRouter= require("app.routes.cover")
local GymanasiumPicsRouter= require("app.routes.gymanasium_pics")
local GymnasiumDescriRouter = require("app.routes.gymnasium_descri")
local TrainnerPicRouter = require("app.routes.trainner_pics")
local TrainnerDescriRouter = require("app.routes.trainner_descri")
local CourseRouter = require("app.routes.course")
return function(app)
app:use("/",HomePageRouter()) --首页
app:use("/judo",judoPageRouter())
app:use("/yogo",yogoPageRouter())
app:use("/freepower",freepowerPageRouter())
app:use("/aerabic",AerabicPageRouter())
app:use("/admin",AdminPageRouter())
app:use("/auth",AuthRouter())
app:use("/upload",uploadRouter())
app:use("/adtopic",AdtopicRouter())
app:use("/cover",CoverRouter())
app:use("/gymnasiumPic",GymanasiumPicsRouter())
app:use("/gymnasiumDescri",GymnasiumDescriRouter())
app:use("/trainnerPic",TrainnerPicRouter())
app:use("/trainnerDescri",TrainnerDescriRouter())
app:use("/course",CourseRouter())
然后依次完善每个路由后面页面上业务处理。值得注意是可以先把每个页面功能完善了,最后再考虑插件的功能。比如session管理等。
第五,由于页面太多,我这里只能具体举例一个页面上业务逻辑处理,以及功能的完善的过程。我就来广告页面的功能实现为例。我首先完善后台页面
local AdminPageRouter = require("app.routes.admin")
app:use("/admin",AdminPageRouter())
在/app/routes中admin.lua文件中加上路由如下
local category = {
first="广告",
second = "柔道",
third = "瑜伽",
fouth = "自由力量",
fiveth = "有氧运动"
}
AdimPageRouter:get("/ad",function(req, res, next)
res:render("admin_ad",{
title = category.first,
})
end)
这里admin_ad对应view中admin_ad.html的静态模板文件。 然后在/app/model/中构造数据模型对象ad_model.lua 代码如下
local DB = require("app.libs.db")
local db = DB:new()
local uuid = require("app.libs.uuid.uuid")
local utils = require("app.libs.utils")
local Ad_Model = {}
function Ad_Model:new(title,coverImage,content)
local unique_number = uuid();
local creat_time = utils.now()
return db:query("insert into ad_topic(title, coverimage, content,ad_uuid,create_time) values(?,?,?,?,?)",
{title,coverImage,content,unique_number,creat_time})
end
function Ad_Model:query_by_uuid(uuid)
local result, err = db:query("select * from ad_topic where ad_uuid=?", {uuid})
if not result or err or type(result) ~= "table" or #result ~=1 then
return nil, err
else
return result[1], err
end
end
function Ad_Model:delete_by_uuid(uuid)
local res,err
res,err = db:query("delete from ad_topic where ad_uuid=?", {uuid})
if res and not err then
return true
else
return false
end
end
function Ad_Model:update_ad_topic_by_uuid(title,coverImage,content,uuid)
return db:query("update ad_topic set title=?,coverimage=?,content=? where ad_uuid=?", {title,coverImage,content,uuid})
end
function Ad_Model:get_total_count()
local res,err
res, err = db:query("select count(ad_id) as c from ad_topic")
if err or not res or #res~=1 or not res[1].c then
return 0
else
return res[1].c
end
end
function Ad_Model:get_all()
local res,err
-- body
res,err = db:query("select * from ad_topic")
if not res or err or type(res) ~= "table" or #res <= 0 then
return {}
else
return res
end
end
function Ad_Model:get_all_uuid()
local res,err
-- body
res,err = db:query("select ad_uuid from ad_topic")
if not res or err or type(res) ~= "table" or #res <= 0 then
return {}
else
return res
end
end
function Ad_Model:get_all_sample()
local res,err
-- body
res,err = db:query("select title,coverimage,ad_uuid from ad_topic")
if not res or err or type(res) ~= "table" or #res <= 0 then
return {}
else
return res
end
end
return Ad_Model
这个时候 就需要在页面上对广告数据进行增删查改的操作,同样就要四个操作数据的接口,所以需要路由上要加上这个四个接口路由管理:
app:use("/adtopic",AdtopicRouter())
同理我会在/app/routes/adtopic.lua中加上详细业务处理:
local lor = require("lor.index")
local AdtopicRouter = lor:Router()
local Admodel= require("app.model.ad_model")
AdtopicRouter:post("/new",function(req, res, next)
local title = req.body.title
local coverimg = req.body.coverimg
local content = req.body.content
local reslut,err = Admodel:new(title,coverimg,content)
if not reslut or err then
res:json({
success = false,
msg = "保存失败"
})
else
res:json({
success = true,
msg = "保存成功",
data = {
id = res.ad_uuid
}
})
end
end)
AdtopicRouter:get("/count",function(req, res, next)
local adcount = Admodel:get_total_count()
res:json({
success = true,
ad_count = adcount
})
end)
AdtopicRouter:get("/:ad_uuid/detail", function(req, res, next)
local uuid = req.params.ad_uuid
local adtopic = Admodel:query_by_uuid(uuid)
res:render("adtopic/adtopic",{adtopic = adtopic })
end)
AdtopicRouter:post("/:ad_uuid/delete", function(req, res, next)
local uuid = req.params.ad_uuid
local isDel = Admodel:delete_by_uuid(uuid)
if isDel then
res:json({
success = true
})
else
res:json({
success = false
})
end
end)
然后会到静态页面上撸js代码,把页面数据与后台数据打通。 我的js水平很烂,这里我也不好意思给大家秀了,具体说来就是用ajax中异步数据请求。
- 开发过程中遇到的坑
这里我遇到2个比较坑得地方
- 上传插件那里出现当有字段数据与文件一起上传时,上传的图片老是有问题。文件老是丢失数据。 经过写测试,打印数据分析后找2个原因有: 我采用webuploader这个js插件开启了
uploader = WebUploader.create({
pick: {
id: '#filePicker',
label: '点击选择图片'
},
formData: {
uid: 123
},
dnd: '#dndArea',
paste: '#uploader',
swf: '../../dist/Uploader.swf',
chunked: false,
chunkSize: 512 * 1024,
server: '../../server/fileupload.php',
// runtimeOrder: 'flash',
// accept: {
// title: 'Images',
// extensions: 'gif,jpg,jpeg,bmp,png',
// mimeTypes: 'image/*'
// },
// 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。
disableGlobalDnd: true,
fileNumLimit: 300,
fileSizeLimit: 200 * 1024 * 1024, // 200 M
fileSingleSizeLimit: 50 * 1024 * 1024 // 50 M
});
我到时开启chunked分块功能,导致数据丢失。
还有改进uploader.lua插件(这个得到 游手 童鞋给我的提示)
local function _multipart_formdata(config)
local form, err = upload:new(config.chunk_size)
if not form then
ngx.log(ngx.ERR, "failed to new upload: ", err)
ngx.exit(500)
end
form:set_timeout(config.recieve_timeout)
local unique_name = uuid()
local success, msg = false, ""
local file,origin_filename, filename, path, extname, url,err
local prefix,suffix
local isFile =false
local params = {}
local paramKey, paramValue
while true do
local typ, res, err = form:read()
if not typ then
success = false
msg = "failed to read"
ngx.log(ngx.ERR, "failed to read: ", err)
return success, msg
end
if err then
ngx.log(ngx.ERR, "read form err: ", err)
end
if typ == "header" then
prefix,suffix = res[1],res[2]
if prefix == "Content-Disposition" then
paramKey = match(suffix, "name=\"(.-)\"")
origin_filename = match(suffix, "filename=\"(.-)\"")
if origin_filename then
isFile = true
else
isFile = false
end
elseif prefix == "Content-Type" then
filetype = suffix
end
if isFile and origin_filename and filetype then
if not extname then
extname = getextension(origin_filename)
extname = extname:lower()
end
if extname ~= "png" and extname ~= "jpg" and extname ~= "jpeg" and extname ~= "bmp" and extname ~= "gif" then
success = false
msg = "not allowed upload file type"
ngx.log(ngx.ERR, "not allowed upload file type:", origin_filename)
return success, msg
end
filename = unique_name .. "." .. extname
path = config.dir.. "/" .. filename
file, err = io.open(path, "w+")
if err then
success = false
msg = "open file error"
ngx.log(ngx.ERR, "open file error:", err)
return success, msg
end
end
elseif typ == "body" then
if isFile then
if file then
file:write(res)
success = true
else
success = false
msg = "upload file error"
ngx.log(ngx.ERR, "upload file error, path:", path)
return success, msg
end
else
success = true
paramValue = res
end
elseif typ == "part_end" then
if isFile then
file:close()
url = '/static/images/'..filename
file = nil
filename = nil
origin_filename = nil
isFile =false
filetype = nil
else
params[paramKey] = paramValue
end
elseif typ == "eof" then
break
end
end
return success, msg, url,params
end
2.在数据模型建模时也遇到一个问题,当时候把页面数写一张表里,这样导致后面接口很难对内容做修改。所以对页面数据都创建要分而治之,以操作最小数据为单元来更新页面数据。
```