zenglMall是使用zengl语言开发商城系统的项目,zenglMall需要通过zenglServer来执行zengl脚本。首先配置zenglServer,让其网站根目录指向zenglMall
页面导航:
zenglMall源代码的相关地址:https://github.com/zenglong/zenglMall 当前版本对应的tag标签为:v0.1.0
zenglMall是使用zengl语言开发商城系统的项目,zenglMall需要通过zenglServer来执行zengl脚本。首先配置zenglServer,让其网站根目录指向zenglMall:
................................. (zenglServer的config.zl配置,省略N行) webroot = "/home/zengl/zenglMall"; // web根目录,指向zenglMall所在的目录 session_dir = "my_sessions"; // 会话目录 session_expire = 1440; // 会话默认超时时间(以秒为单位) session_cleaner_interval = 3600; // 会话文件清理进程的清理时间间隔(以秒为单位)
然后运行zenglServer(v0.1.0的zenglMall对zenglServer的最低版本要求是v0.23.0,还需要开启mysql,magick,pcre以及openssl模块):
[zengl@localhost zenglServer]$ ./zenglServer -v zenglServer version: v0.23.0 zengl language version: v1.8.3 [zengl@localhost zenglServer]$ ./zenglServer [zengl@localhost zenglServer]$ tail -f logfile port: 8083 process_num: 1 webroot: /home/zengl/zenglMall session_dir: my_sessions session_expire: 1440 cleaner_interval: 3600 remote_debug_enable: False remote_debugger_ip: 127.0.0.1 remote_debugger_port: 9999 zengl_cache_enable: False shm_enable: False shm_min_size: 307200 verbose: True request_body_max_size: 204800, request_header_max_size: 5120 request_url_max_size: 1024 URL_PATH_SIZE: 120 FULL_PATH_SIZE: 200 pidfile: zenglServer.pid bind done accept sem initialized. process_max_open_fd_num: 1024 Master: Spawning child(0) [pid 2375] Master: Spawning cleaner [pid 2376] ------------ cleaner sleep begin: 1607756884 epoll max fd count : 896
要访问商城首页和进入后台管理界面,还需要创建数据库表结构,首先修改zenglMall根目录中的config.zl配置:
config['db_host'] = 'localhost'; // 填写mysql数据库ip config['db_port'] = 3306; // 填写mysql数据库端口 config['db_user'] = 'root'; // 填写mysql用户名 config['db_passwd'] = '123456'; // 填写mysql密码 config['db_name'] = 'testmall'; // 填写mysql数据库名 config['version'] = '0.1.0'; // zenglMall版本号,无需修改 config['site_name'] = 'zenglMall'; // 站点名称 config['site_desc'] = 'mall made by zengl language'; // 站点描述 // 支付宝的APPID(发起请求的应用ID) config['app_id'] = ''; // 支付完成后的异步通知地址,必须是外网可以访问到的地址 config['notify_url'] = 'http://domain_url/notify_url.zl'; // 支付完成后跳转返回到商家的地址 config['return_url'] = 'http://domain_url/return_url.zl'; // 签名方式,目前测试脚本只支持最新的RSA2方式,所以不需要修改 config['sign_type'] = 'RSA2'; // 支付宝网关,沙箱的网关地址和正式环境的网关地址不同 config['gateway_url'] = 'https://openapi.alipaydev.com/gateway.do'; // 商户私钥 config['merchant_private_key'] = ''; // 支付宝公钥 config['alipay_public_key'] = '';
请确保上面数据库配置的正确性,如果没有创建过testmall(假如你在配置中使用了testmall作为数据库名的话),就先创建该数据库。如果要测试支付功能的话,则还需要配置与支付宝相关的APPID,商户私钥等。
假设zenglServer所在的系统的ip为192.168.1.113,那么访问 http://192.168.1.113:8083/install/create_table.zl 该脚本会自动在数据库中创建所需的表结构,例如 admin_users(后台管理用户表),category(商品分类表),goods(商品表)等,并在admin_users表中插入一条初始数据。该脚本执行成功后,会返回后台用户名,密码之类的信息,如下所示:
创建zenglMall数据库表结构
安装会生成install.lock锁文件,以防止误操作。在有锁文件的情况下,再次执行create_table.zl脚本,就会提示 lock file exists ,并阻止脚本继续执行。
安装完毕后,就可以通过 http://192.168.1.113:8083/index.zl 的地址看到商城的首页了:
初始化安装后的商城首页
初始化安装后,一开始首页的导航栏只有一个会员中心的菜单,更多的菜单需要在后台通过添加顶层分类的形式来添加。页面上面还没有商品信息,商品信息也需要在管理后台添加。
接下来,我们就可以使用 admin 和 admin@123456 的初始后台管理员的用户名和密码,通过 http://192.168.1.113:8083/admin/login.zl 登录后台。
登录成功后的后台地址:http://192.168.1.113:8083/admin/admin.zl ,此地址是概览页面,该页面可以看到一些基本信息,例如:mysql版本号,zenglServer版本号,zengl语言版本等等,还可以在管理后台添加分类,添加商品,以及进行订单管理等:
后台概览页面
在后台添加了分类和商品后,就可以在商城首页看到这些分类和商品信息了:
添加分类和商品信息后的首页示例
点击商品链接可以进入商品详情页面:
商品详情页面
如果要测试支付功能,除了要配置上面提到过的支付宝的APPID,商户私钥等配置外,还必须确保配置中的异步通知地址能被外网访问到(因为支付完成后,支付宝会将支付完成情况通过这个地址反馈给服务器,因此,ip地址或域名必须能被外网访问到),对于本地测试环境,可以利用ngrok之类的工具,将外网请求转发到本地测试环境。在配置好这些后,就可以点击商品详情页面中的立即购买按钮,进入确认支付页面(如果没有登录过,会提示登录,如果没注册过,可以在登录页面点击立即注册按钮进行注册):
确认支付页面
在确认支付页面,需要填写收货人的姓名,电话,地址等信息,填写完后,点击确认支付按钮,就会跳转到支付宝的支付页面:
支付宝的支付页面
在支付页面完成支付操作后,就会跳转回商家页面,并提示支付成功的信息:
支付完成后返回的商家页面
在前台用户会员中心的订单列表页面,以及管理后台的订单列表页面都可以看到相关的订单信息。
通过会员中心的订单列表,可以查看某个订单的订单详情
在管理后台的订单详情页面可以将订单设置为待收货状态(表示已发货),还可以在订单详情页面设置商家备注,将快递单号等信息写入进去,这样前台用户就可以知道快递信息了。
而前台用户在会员中心的订单详情页面可以执行确认收货的操作。前台用户还可以在会员中心修改用户信息,例如修改默认的收货地址等,还可以在会员中心修改密码。
商城前台页面(例如:首页,点击分类后进入的商品列表页及商品详情页面等)相关的脚本都位于根目录中,包括config.zl商城的配置脚本也在根目录。
和前台用户会员中心相关的脚本,放置在user_admin目录中,除了前台用户的登录脚本,登录脚本(login.zl)还是在根目录。
商城后台页面相关的脚本,则放置在admin目录中。大部分脚本的代码中都添加了相关的注释信息,方便对代码进行分析,例如根目录中的mysql.zl脚本:
// Mysql数据库类,提供一些和Mysql数据库操作相关的方法 class Mysql con; error_tpl; /** * 当操作数据库发生错误时,直接退出脚本,同时会返回500错误给客户端,所有的500错误对应的具体错误原因都会记录到zenglServer日志中, * 如果使用了bltFatalErrorCallback模块函数设置过运行时错误回调函数的话,还会调用用户自定义的回调函数来处理错误信息 */ fun error(obj, sql='') Mysql obj; data['error'] = mysqlError(obj.con); mysqlClose(obj.con); if(obj.error_tpl) data['title'] = 'Mysql错误'; print bltMustacheFileRender(obj.error_tpl,data); endif bltExit(data['error'] + (sql ? ' sql: ' + sql : '')); endfun // 初始化mysql数据库连接,并将mysql连接设置到obj的con成员中 fun init(obj, config, error_tpl) Mysql obj; obj.error_tpl = error_tpl; obj.con = mysqlInit(); if(!mysqlRealConnect(obj.con, config['db_host'], config['db_user'], config['db_passwd'], config['db_name'], config['db_port'])) Mysql.error(obj); endif if(mysqlSetCharacterSet(obj.con, "utf8")) Mysql.error(obj); endif endfun // 根据sql语句执行查询操作,返回一条查询记录(返回数组的各成员对应该条查询记录的各个字段) fun fetchOne(obj, sql) Mysql obj; if(mysqlQuery(obj.con, sql)) Mysql.error(obj); endif result = mysqlStoreResult(obj.con); if(!mysqlFetchResultRow(result, &result_array)) result_array = bltArray(); endif mysqlFreeResult(result); return result_array; endfun // 根据sql语句执行查询操作,返回所有的查询记录(返回数组的每个成员都对应一条查询记录) fun fetchAll(obj, sql) Mysql obj; if(mysqlQuery(obj.con, sql)) Mysql.error(obj, sql); endif result = mysqlStoreResult(obj.con); return_array = bltArray(); while(mysqlFetchResultRow(result, &result_array)) return_array[] = result_array; endwhile mysqlFreeResult(result); return return_array; endfun // 将str对应的语句进行mysql转义,让其可以安全的用于sql语句中(通常用于拼接sql语句时,需要执行转义操作) fun Escape(obj, str) Mysql obj; return mysqlRealEscapeString(obj.con, bltStr(str)); endfun // 将datas数组作为数据库记录(数组中的每个成员都对应记录中的一个字段,成员key对应字段的列名,成员的值对应字段的值)插入到table表中 fun Insert(obj, table, datas) Mysql obj; vals = keys = ''; len = bltCount(datas); for(i=0,j=0;bltIterArray(datas,&i,&k,&v);) keys += "`" + Mysql.Escape(obj, k) + "`"; vals += "'" + Mysql.Escape(obj, v) + "'"; if(++j < len) keys += ','; vals += ','; endif endfor if(len > 0) sql = "INSERT INTO `"+table+"` (" + keys + ") VALUES (" + vals + ")"; if(mysqlQuery(obj.con, sql)) Mysql.error(obj, sql); endif endif endfun // 将datas数组作为数据库记录(数组中的每个成员都对应记录中的一个字段,成员key对应字段的列名,成员的值对应字段的值)更新到table表中, // where表示更新条件,即通过sql的where语句来指定哪些数据库记录需要被更新 fun Update(obj, table, datas, where = '') Mysql obj; key_vals = ''; len = bltCount(datas); for(i=0,j=0;bltIterArray(datas,&i,&k,&v);) key_vals += "`" + Mysql.Escape(obj, k) + "`=" + "'" + Mysql.Escape(obj, v) + "'"; if(++j < len) key_vals += ','; endif endfor if(len > 0) sql = "UPDATE `"+table+"` SET " + key_vals + (where != '' ? ' WHERE ' + where : ''); if(mysqlQuery(obj.con, sql)) Mysql.error(obj, sql); endif endif endfun // 执行原始的sql语句,脚本中也可以手动拼接原始的sql语句来执行相关的数据库操作(例如插入,更新之类的语句) fun Exec(obj, sql) Mysql obj; if(mysqlQuery(obj.con, sql)) Mysql.error(obj); endif endfun endclass
zenglMall的前端模板是使用bootstrap + vue来编写的,因此,请尽量使用火狐,谷歌或者微软的Edge浏览器来进行测试,IE11在测试当前版本时发现,在后台编辑商品信息时会自动过滤掉CKEditor编辑器中的图片信息,所以IE11之类的IE系列的浏览器还存在兼容问题,在后续版本开发中,如果有时间的话有可能会去处理这些浏览器兼容问题,不过就当前版本而言,还是尽量使用火狐,谷歌之类的浏览器来进行测试。
zenglMall使用MIT开源协议,没有什么使用上的限制,你可以对它进行任意的修改,发布,以及上线进行商业运作等。在根目录的readme.md文档中也记录了zenglMall的安装和使用说明,如果要使用nginx进行反向代理的话(由nginx处理静态文件请求,由zenglServer来运行zengl脚本),也可以在readme.md文档中找到相关的说明。
人生只有一次,如果不按照自己的意愿去活,那才是最大的失败。
—— 创业时代