目录
在本章的开发过程中,我们建立了一个简单的后台系统,一个是希望对人员进行管理(主要完成人员身份的设置)。在前端,不同身份(教师还是学生)可以操作的界面是不同的,教师可以领取教学任务,而学生能够选择已有教师领取任务的课程。
我们还对课程进行管理维护,目的是统计可以开课的课程信息。如果有教师领取了该课程的教学任务,同时有学生选择了这门课程,该课程还尚未开课,此时可以对课程进行开课。后台点击开课按钮时,即触发上节提到的轮询向选择了该门课程的同学发送开课模板信息。
1.发模板消息时两个重要方法的实现
(1)getAccessToken的实现
在实现getAccessToken时,与第二章不同。第二章是需要用户授权获得页面code,之后通过页面code换取网页授权access_token。而在本章,由于向已关注公众号的用户发送模板消息时,该用户的wxid已经知道,我们只需要微信公众平台上已有的appID和appSecret两个参数获得后台发送消息、处理事件的普通access_token即可。(参考 网页授权 | 微信开放文档 中“关于网页授权access_token和普通access_token的区别”的说明)。
按照微信开发文档中关于普通access_token获取说明
(https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html),接口调用请求地址格式为:
https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
其中,参数grant_type是固定的,填写client_credential,而appid和appsecret在第二章时介绍过,应在微信开放平台后台可以看到的。
调用成功后,该接口返回一个json字符串,格式为:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
还需注意的是,access_token有7200秒的有效期,即无需重复调用该接口,使用上次获取的,处于有效期内的access_token就可以完成需要access_token程序中。
鉴于此,本文中,将调用后的access_token和有效期、获取时间等存放在数据库中,下次需要使用时,根据当前时间计算是否过期,未过期的情况下不再重复调用。
数据表的实现
CREATE TABLE `sys_config_temp` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`access_token` varchar(200) DEFAULT NULL,
`expires_in` int DEFAULT NULL,
`receiveTime` int DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `sys_config_temp` VALUES(1,"non-receive",7200,1680665312);
后台调用代码的实现
function getAccessToken($appid,$appsecret)
{
$access_token = $back->GetAccessToken();
if($access_token == 'non-receive') // 未获取或已超时
{
//构造接口格式重新获取
$url = "https://api.weixin.qq.com/cgi-bin/token?
grant_type=client_credential&appid=$appid&secret=$appsecret";
$result = $this->_https_request($url);
$jsoninfo = json_decode($result, true);
$access_token = $jsoninfo['access_token'];
$expires_in = $jsoninfo['expires_in'];
// 向数据库中更新
$back->UpdateAccessToken($access_token,$expires_in);
}
return $access_token;
}
在back.class.php中实现上述辅助的数据库操作为:
function GetAccessToken()
{
$sql = "SELECT * FROM sys_config_temp WHERE ID=1";
$query = $this->query($sql);
$access_token = "non-receive";
if($query->num_rows!=0){
$row = $this->fetch_array($query);
$rec_Time = $row['receiveTime'];
$exp_Time = $row['expires_in'];
$now_Time = time();
// 如果没有超时则使用数据库中的access_token
if($now_Time-$rec_Time<$exp_Time)
{
$access_token = $row['access_token'];
}
}
return $access_token;
}
function UpdateAccessToken($aToken,$expires)
{
$now_Time = time();
$sql = "UPDATE sys_config_temp SET
receiveTime=$now_Time,access_token='$aToken',
expires_in=$expires WHERE ID=1";
return $this->query($sql);
}
(2)request_post的实现
请注意curl的参数设置,设置错误时微信服务器不能正确返回数据。
function request_post($url = '', $param = '') {
if (empty($url) || empty($param)) {
return false;
}
$postUrl = $url;
$curlPost = $param;
$ch = curl_init();//初始化curl
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
curl_setopt($ch, CURLOPT_URL, $postUrl); // 提交地址
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); // 数据内容(模板参数)
$data = curl_exec($ch);//运行curl
curl_close($ch);
return $data; // 返回执行结果
}
2.后台两个简单的页面实现
(1)后台用户管理页面
这里我们使用了基于PHP的一个著名的引擎模板smarty,它的作用是将前端html和后端php分离,而不是在php文件中嵌入html。
在users.php中,我们使用下述方式完成模板赋值和显示:
// 查询所有人员
$user_list = $back->queryUsers();
// 隐私脱敏
foreach($user_list as $i => $item)
{
$user_list[$i]["u_name"] =substr_cut($user_list[$i]["u_name"]);
$user_list[$i]["u_wxid"] =substr_cut($user_list[$i]["u_wxid"]);
$user_list[$i]["u_mobile"] =substr_cut($user_list[$i]["u_mobile"]);
}
// 赋值给模板
$smarty->assign('user_list',$user_list);
$smarty->assign('cur', 'users');
$smarty->display('users.html');
在模板文件users.html中,按照smarty的使用方式,我们有
<tbody id="tableText">
<!-- {foreach from=$user_list item=user} -->
<tr class="odd gradeX">
<td><input type="checkbox" name="chk[]" value="{$user.u_id}"></td>
<td>{$user.u_id}</td>
<td>{$user.u_name}</td>
<td>{$user.u_mobile}</td>
<td>{$user.u_wxid}</td>
<td><!--{if $user.u_type eq 1}-->
教师<!--{else}-->学生<!--{/if}--></td>
<td align="center"><button type="button" class="btn btn-primary"
onclick="openlayer({$user.u_id})">修改</button>
| <button type="button" class="btn btn-warning"
onclick="delconfirm({$user.u_id})">删除</button></td>
</tr>
<!-- {/foreach} -->
</tbody>
这里,我们还使用了基于jQuery的ajax技术,在处理“修改”和“删除”时,我们不再刷新整个页面,而是通过ajax异步获取后台数据,只刷新tbody部分内容。
// 弹出层,确定删除对话框
layer.confirm('确定删除?',
{
icon:7,
title:'删除人员',
btn:['确定','取消']
},function(){
$.ajax({
url: 'https://www.XXX.cn/classBack/interface',
data:{op:'delUser'
uid:uid},
type: 'POST',
dataType: 'json',
success: function (result) {
var data = result.data;
if (data) {
var str = "";//把数据组装起来
for (var i = 0; i < data.length; i++) {
str += "<tr class=\"odd gradeX\"><td>
<input type=\"checkbox\" name=\"chk[]\" value=\""
+ data[i].u_id + "\"></td>";
str += "<td>" + data[i].u_id +
"</td><td>" + data[i].u_name +
"</td><td>" + data[i].u_mobile +
"</td><td>" + data[i].u_wxid;
if (data[i].u_type==1)
{
str += "</td><td>教师</td>";
}
else
{
str += "</td><td>学生</td>";
}
str += "<td align=\"center\">
<button type=\"button\" class=\"btn btn-primary\"
onclick=\"openlayer("
+ data[i].u_id + ")\">修改</button>
| <button type=\"button\" class=\"btn btn-warning\"
onclick=\"delconfirm("
+ data[i].u_id + ")\">删除</button></td></tr>";
}
//只刷新tbody部分
$("#tableText").html(str);
layer.closeAll('dialog');
}
},
error: function (err) {
console.log(err);
}
});
})
(2)后台课程管理页面
课程管理中值得关注的是计算是否达到开课标准部分,我们在back.class.php中实现了一个queryCourse_st的方法如下:
// 返回课程及开课结果
function queryCourse_st($c_id)
{
$sql = "";
if($c_id <= 0) // 小于等于0时查询全部课程
{
$sql = "SELECT a.*,b.c_state FROM course a
LEFT JOIN teaching b on a.ID = b.c_ID";
}
else
{
$sql = "SELECT a.*,b.c_state FROM course a
LEFT JOIN teaching b on a.ID = b.c_ID WHERE a.ID = $c_id";
}
$course_list = array();
$query = $this->query($sql);
// 将查询结果转化为数组列表
while ($row = $this->fetch_array($query)) {
$course_list[] = array(
"c_name" => $row['c_name'],
"c_id" => $row['ID'],
"c_state" => $row['c_state'],
"c_credit" => $row['c_credit'],
"c_teacher" => "",
"c_stCount" =>0,
"c_isCanStart"=>0
);
}
// 对每一个查询结果进行判断
// 判断依据:选课人数>0,教师已选课,课程处于未开课状态
foreach($course_list as $i => $item)
{
$c_item_id = $item["c_id"];
$t_bSeletion = false;
$s_bSelection=false;
$sql = "select a.t_name from teacher a,
teaching b where a.ID=b.t_ID and b.c_id=$c_item_id";
$query = $this->query($sql);
if ($query->num_rows!=0)
{
$teacher = $this->fetch_array($query);
$course_list[$i]["c_teacher"] = $teacher["t_name"];
$t_bSeletion = true;
}
$sql = "select count(*) as cn from selection
where c_id=$c_item_id";
$query = $this->query($sql);
if ($query->num_rows!=0)
{
$cnum = $this->fetch_array($query);
$course_list[$i]["c_stCount"] = $cnum["cn"];
if ( $cnum["cn"] > 0)
$s_bSelection = true;
}
if($t_bSeletion && $s_bSelection && $item["c_state"] ==0)
{
$course_list[$i]["c_isCanStart"] =1;
}
}
// 返回结果列表
return $course_list;
}
本章小结
在本章,我们主要通过调用接口获取普通access_token,并通过微信服务号模板消息接口向已选课程的同学发送模板消息。
本章后台使用的基于php的smarty引擎、jQuery的ajax异步刷新技术等,将在后续章节后台不断完善中继续使用,希望大家掌握。
补记:作者是在业余时间开展创作,随着年龄的增长,精力实在有限。前端时间由于工作上的原因,停更的长达2年之久,深表歉意。作者一定怀着对自己喜欢的事业崇敬心情,将本文创作完成!希望得到广大微信公众号开发、H5开发、PHP开发或者其他技术的爱好者的支持和鼓励,请多多关注和支持,我坚信,我不是一个人在战斗!
本章代码,请在此处下载。对本章内容有任何疑问,欢迎在评论区留言!您的鼓励是作者能够继续前行的莫大动力~~