澳门新萄京:完美利用Yii2微信后台开发的系列总
分类:澳门新萄京最大平台

李秉骏:在Phonegap下实现oAuth认证

2012/07/18 · HTML5 · 2 评论 · 来源: 李秉骏     · HTML5

本文由李秉骏(@CashLee李秉骏)投稿于伯乐在线,也欢迎其他朋友投稿。提示:投稿时记得留下微博账号哦 澳门新萄京 1

前段时间做过两次关于Phonegap的现场交流会议分享。基本上把Phonegap的一些特性和大家交流了一下,大家对于Phonegap的 兴趣也是非常多的。但是因为Phonegap相对于原生应用来说,只有一个View,这个View就是一个Web的容器,这使得Phonegap就存在很 多限制。其中一部分的限制我们已经通过HTML5的API以及Phonegap为我们搭建的桥去实现了,另外一部分我们就得通过Phonegap plugins来实现,而实际上我个人认为Phonegap最强大的地方也在于有那么大的一个群体在为他提供各种各样的Plugins,以便去应对实际项 目中遇到的问题。

我记得在和大家交流的时候大家经常会问Phonegap如何做本地的缓存啊(WebSQL),如何贴近原生应用(这个涉及到架构,界面渲染问题,这 里我也不好深入讲,毕竟不是本文要讨论的内容),还有一个很头疼的问题就是如果要做一个开放平台的应用,如何实现oAuth认证。此前我也遇到过类似的一 些情况,当我再次遇到这个棘手的问题的时候,我相信一定也有Phonegap的粉丝遇到类似的情况的。于是我就总结下来何大家探讨一下如何解决这个问题 吧。

首先目标:解决oAuth认证。

制定计划:1. 知道oAuth原理;2.了解Phonegap在处理这个问题时候的运行机制;3. 制定计划实现代码。

下面我们就来一步一步地分析,看如何解决这个情况吧。(因为我在项目中遇到的是腾讯微博开放平台的oAuth认证,那么下面我就用腾讯oAuth认证为例吧)

关于oAuth认证,相信做过开放平台应用的朋友都已经非常熟悉了,如果你还没有做过或者对于oAuth认证流程非常不了解,那么我建议你先了解一 下原理,在这里我不希望花太多的篇幅去介绍这个东西,因为在很多地方都可以找到,下面我推荐两个地址方便大家去阅读,一定要阅读,这会对你理解下面的文章 有莫大的帮助的。

腾讯微博开放平台:

新浪微博开放平台:

当然在这里上面需要阐述说明的是oAuth认证机制是一个通用的手法,但是因为每个开放平台有自己的政策,因此可能在其中稍有改变,而且最终获得的权限也会各不相同。而最近新浪微博实在太多坑爹的事情了,实在忍受不了,于是我转战到腾讯的平台了。

好的,如果你看完了oAuth认证的流程,就直接到这里来。众所周知,在oAuth认证的流程中,有一个授权页面,而这个授权页面是通过开放平台提供的,具体的样式见下图:

澳门新萄京 2

这个页面用于输入开放平台的帐户以及密码,通过授权获取响应的openid以及openkey,最终换取access-token(待会我会结合腾讯微博oAuth认证流程的特点,以及代码和大家分析的)。

这个页面是弹出的,如果在Phonegap里面做的话会很奇怪:1,因为属于弹窗,在Phonegap中本身就是一个WebView如果你还弹的话 就会飞到了Safari的浏览器中,这就跳出应用本身,跳出去认证还有戏吗?2,通过iFrame,首先体验非常不好,其次iFrame本身又属于跨域的 问题,这就不好解决了(为什么体验不好呢,主要是因为授权页面的样式是不固定的,类似腾讯微博开放平台,就比新浪的授权页面做得差,根本不和手机匹配的, 而且有些做得好的,认证页宽度就是320px,就占了你整个应用的版面,体验很不好)那么Phonegap中该如何实现呢?

带着问题,我们就希望在Phonegap中再度引入一个WebView。刚刚提到Phonegap的强大还在于很多人以及官方的团队,为其提供了一 套很好的插件机制,以解决各种各样的需要。在Phonegap中有一个插件叫做ChildBrowser,顾名思义就是:子浏览器。(其实我在上两次的 Phonegap专题技术分享中以及提及到让大家用这个东西去解决,不过当时分享时间有限只能够草率带过,抱歉)子浏览器的作用其实就是让你在 Phonegap应用内部调起一个浏览器的View,让你进行pdf,图片,视频,甚至网页阅读的工具。(实际上你看我上面的截图,就是用 ChildBrowser来实现的)这就好了,这就可以让你调起浏览器而且不跳出应用本身了,可以很好地解决oAuth认证的问题。 ChildBrowser下载地址:

在地址上面,你应该已经看到ChildBrowser的安装方法以及使用方法了,非常简单,真正的即插即用。如果你觉得英文太难,这我就帮不了你 了,你就自行Google翻译一下吧。相信你很快就可以做出一个ChildBrowser的Demo的。在这个地址上面,其实你返回上一层目录,其实你也 已经看到各式各样的Phonegap Plugins,通过这些东西,你还可以调用起手机内部更多有趣的资源的!这个就要靠你自己去发掘啦!(其他平台的应用也有相应的插件的Android开 发者不要骂果粉哦!)

好了慢慢地我们就要涉及到代码部分了。首先我们看看调用ChildBrowser的Javascript代码:

JavaScript

cb = window.plugins.childBrowser; /* if(cb != null) { cb.onLocationChange = function(loc){ root.locChanged(loc); };//地址发生改变时候执行的函数 cb.onClose = function(){root.onCloseBrowser(); };//通过js关闭ChildBrowser的办法 cb.onOpenExternal = function(){root.onOpenExternal(); }; */ cb.showWebPage("");

1
2
3
4
5
6
7
8
        cb = window.plugins.childBrowser;
/*
        if(cb != null) {
        cb.onLocationChange = function(loc){ root.locChanged(loc); };//地址发生改变时候执行的函数
        cb.onClose = function(){root.onCloseBrowser(); };//通过js关闭ChildBrowser的办法
        cb.onOpenExternal = function(){root.onOpenExternal(); };
*/
        cb.showWebPage("http://google.com");

其中cb就是初始化的ChildBrowser,而showWebPage就是调起这个页面的方法。可见代码中要打开的网址就是 Google.com啦,这个地球人都能够看得懂了。于是我们就可以马上想到我们要用ChildBrowser打开的网址是我们在网上指定的应用授权站点 了。而我是部署在SAE上面的,所以下面的例子也用PHP来说吧,期待语言也是相同的道理,转义就可以了。在说代码之前,我们先来说说具体通讯的流程,以 及我们接下来要达到的目标。

澳门新萄京 3
在这里,我们的手机端是通过访问SAE服务器,由SAE服务器管理数据并与腾讯微博开放平台通讯的,这里手机端并没有直接和腾讯微博开放平台通讯(我这样 处理的原因是1,方便在服务器端管理帐户,这样的话可以观察自己的应用的帐户状况;2,服务器端实现推送机制,方便管理token以及做api;3,服务 器端还可以和其他开放平台帐户绑定)。因此,我们的整套认证方案会在服务器端完成。

而根据腾讯微博开放平台,我们首先会在开放平台上面注册自己的应用,注册的流程以及办法我不说了,注册的地址是:,注册你的应用后,你相应能够获得的东西是:

JavaScript

应用名称:mobile_test_api 应用类型:客户端应用 App Key:88888888 App Secret:ainidenideiienfeomeomroemrome

1
2
3
4
应用名称:mobile_test_api
应用类型:客户端应用
App Key:88888888
App Secret:ainidenideiienfeomeomroemrome

在这里我的App key以及App Secret是假的(你懂的,你应该有你自己的),下面我们就使用腾讯提供给我们的PHP SDK,下载地址:。有了SDK后我们就可以把SDK放到自己的环境上面,然后配置服务器端的代码了。下图是我简单配置的服务端的代码,lib下存放的就是腾讯微博的sdk。当然实际生产环境和这个有不同。这里仅仅作为演示使用:

澳门新萄京 4

下面就根据腾讯微博认证的流程,逐一讲解一下这些文件以及内部的代码吧。

index.php

PHP

<?php require_once 'app_config.php'; $url=" header('Location:'.$url);

1
2
3
4
5
6
<?php
require_once 'app_config.php';
 
$url="https://open.t.qq.com/cgi-bin/oauth2/authorize?client_id=".$client_id."&APP_KEY=".$app_key."&wap=2&response_type=code&redirect_uri=http://yoururl.com/get_auth.php";//指定URL地址
 
header('Location:'.$url);

这里引入的app_config.php

PHP

<?php $client_id = '8888888888'; $app_key = 'anienineiienrieireowq2839289';

1
2
3
4
5
<?php
 
$client_id = '8888888888';
 
$app_key = 'anienineiienrieireowq2839289';

因为根据腾讯微博开放平台,我们第一步要获取的是Code,如下所述,我们要做的就是做好配置,获取这个Code

JavaScript

第一步:请求code 请求方法: GET 请求地址: 返回结果: 如果授权成功,授权服务器会将用户的浏览器重定向到redirect_uri,并带上code,openid和openkey等参数,重定向的url如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
第一步:请求code
 
请求方法:
GET
 
请求地址:
 
https://open.t.qq.com/cgi-bin/oauth2/authorize?client_id=APP_KEY&amp;response_type=code&amp;redirect_uri=http://www.myurl.com/example
 
返回结果:
如果授权成功,授权服务器会将用户的浏览器重定向到redirect_uri,并带上code,openid和openkey等参数,重定向的url如下:
 
http://www.myurl.com/example?code=CODE&amp;openid=OPENID&amp;openkey=OPENKEY

具体需要请求附带的参数,必须要按照oAuth2.0鉴权的页面提示的进行。()

然后我们再来看看我们所配置的文件:

get_auth.php

PHP

<?php require_once 'app_config.php'; $code = $_REQUEST['code']; $openid = $_REQUEST['openid']; $openkey = $_REQUEST['openkey']; $url = ""; $message = file_get_contents($url); /* success to print the access token message */ $access = explode("=",$message); print_r("<br />"); $access_message = explode("&",$access[1]); $access_token = $access_message[0]; $user_name = $access[4]; print_r($access_token ." " . $user_name);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
 
require_once 'app_config.php';
 
$code = $_REQUEST['code'];
 
$openid = $_REQUEST['openid'];
 
$openkey = $_REQUEST['openkey'];
 
$url = "https://open.t.qq.com/cgi-bin/oauth2/access_token?client_id=".$client_id."&client_secret=".$app_key."&grant_type=authorization_code&code=".$code."&redirect_uri=http://yoururl.com/get_auth.php";
 
$message = file_get_contents($url);
 
/* success to print the access token message */
 
$access = explode("=",$message);
 
print_r("<br />");
 
$access_message = explode("&",$access[1]);
 
$access_token = $access_message[0];
 
$user_name = $access[4];
 
print_r($access_token ."   " . $user_name);

其实到以上为止,我们的配置文件已经弄好了。在这个配置文件中,实际上我们要做的就是腾讯微博开放平台中提及的第二步:

JavaScript

第二步:请求accesstoken 请求地址: 返回结果: 返回字符串: access_token=ACCESS_TOKEN&expires_in=60&refresh_token=REFRESH_TOKEN

1
2
3
4
5
6
7
8
9
第二步:请求accesstoken
 
请求地址:
 
https://open.t.qq.com/cgi-bin/oauth2/access_token?client_id=APP_KEY&amp;client_secret=APP_SECRET&amp;redirect_uri=http://www.myurl.com/example&amp;grant_type=authorization_code&amp;code=CODE
 
返回结果:
返回字符串:
access_token=ACCESS_TOKEN&amp;expires_in=60&amp;refresh_token=REFRESH_TOKEN

如果你现在已经配置好你的服务端口,已经配置好手机端的ChildBrowser,你就已经可以在手机上面看看整个认证的流程了。现在的工作已经完 成了大部分了,不过细心的朋友可能会发现,对啊,认证是完成了,手机上还是没有获得授权啊,因为授权后的信息还不能够通过手机去获取。不要 急,ChildBrowser有趣的地方还没有完呢。在手机端上面我们完成了oAuth认证,总有一些参数返回,不管accesstoken是否存在手机 端,你总得有个帐户机制和服务端通讯。我的服务端在SAE上面,我就建立一个唯一澳门新萄京,id给手机,于是我就建立了一个帐户机制,存在服务端上,服务端上存储的东西是:

MySQL

CREATE TABLE IF NOT EXISTS `auth_user` ( `id` int(10) NOT NULL AUTO_INCREMENT, `muser` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `openkey` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

1
2
3
4
5
6
7
8
9
10
CREATE TABLE IF NOT EXISTS `auth_user` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `muser` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `openkey` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

其实这个表也还没有完善,我必须还要纪录这个用户是否在线(如果有推送机制)。此后手机端和服务端通讯就通过上面的id以及token等的信息进行 通讯,再通过服务端想腾讯微博进行api的通讯,获取我们想要的信息。那么认证后我们通过什么途径拿到认证后返回的信息呢?大家看看上面JS控制 ChildBrowser的代码。会发现里面有一个方法:

JavaScript

cb.onLocationChange = function (loc){ console.warn(loc); };

1
cb.onLocationChange = function (loc){ console.warn(loc); };

如果你在xCode上面跑这段代码的话,你会发现loc打出来的是每次ChildBrowser里面浏览的网页改变的地址。这个时候我们就可以顺水 推舟,根据这里提供的办法,用url的方式把地址返回到Phonegap负责逻辑处理的JS代码中,同时将相关需要通讯的信息也返回。返回后还可以通过回 调的方式执行关闭ChildBrowser的代码:

JavaScript

cb.close();

1
cb.close();

当然,你还可以执行更多异步请求的代码。至于说还可以通过怎么样的方式进行通讯其实还有很多办法,我这里仅仅是提供一下思路引导以及方法。具体的 话,还要实践出真理论,做到非常安全的通讯还值得我们继续深入探讨。那么我要介绍的大概就到这里为止。因为实际项目中我们还有push notification的机制,所以此后我应该还会联同@Jeff_Kit 实现一下Phonegap的推送方案,并整理出sdk,成文后开放出来方便大家交流。

对于本文如果有什么疑问或者建议都可以直接向我反馈,我的新浪微博是:@CashLee李秉骏 ,我还经常分享一些代码片段在github上面(开源的精力不多,所以开源项目较少,希望日后增加吧。)我的Github账号, 欢迎您和我随时进行交流,也希望Phonegap的中国开发者社区会变得越来越精彩。

注意:ChildBrowser控件在实际环境中因为安全问题可能需要修改,通讯过程中参数也建议加密。:-)

 

本文由李秉骏(@CashLee李秉骏)投稿于伯乐在线,也欢迎其他朋友投稿。提示:投稿时记得留下微博账号哦 澳门新萄京 5

【如需转载,请标注并保留原文链接和作者等信息,谢谢合作!】

 

 

1 赞 收藏 2 评论

澳门新萄京 6

网上有很多关于YII2.0微信开发教程,但是太过复杂凌乱,所以今天在这里给大家整理总结利用Yii2微信后台开发的系列了,给需要的小伙伴们参考。

上一篇文章我们介绍快速搭建YII2框架advanced安装配置

管理系统的操作日志如何做成通用的模块一直是个让我头疼的问题,不过看了博客园里的某篇文章后,现在基本解决了。
  相关文章链接:《系统操作日志设计》
  在开始做之前,必须把两个日志分清楚,那就是普通操作日志业务操作日志,这两者有何区别?
  在我理解,普通操作日志就是单表的操作记录,而业务操作日志则就是一系列的普通操作日志的集合。
  打个比方,用户需要购买一样宝贝,已经到了下单那步,下单就是个业务,这个业务背后就是一系列的业务,如:
  生成订单 → 生成商品快照 → 发送一条站内信 → 删除购物车里对应宝贝
  这样一个下单操作就包含了4部分,可以把这4部分看成是4张表,分别对这4张表进行对应的操作,就实现了业务。
  但今天我要讲的不是业务操作日志,因为不同项目的业务不尽相同,所以它无法做成通用模块,而我要讲的,就是普通操作日志。
  上面解释了一大段,下面干货就要亮相了,先洗把脸清醒下。
  ……
  首先,哪些地方需要记录操作日志?执行insert、update、delete这3个操作的时候,就需要进行日志,而日志执行的先后顺序如下
insert
在insert后执行

引言

一:接入微信

本篇文章将会配合YII2框架原有的登录机制模板快速的实现用户后台的登录

update
在update前后都要执行,操作前获取操作前数据,操作后获取操作后数据

微服务架构是一项在云中部署应用和服务的新技术。大部分围绕微服务的争论都集中在容器或其他技术是否能很好的实施微服务,而红帽说API应该是重点。

Yii2后台配置

1:在数据库建立对应的用户信息表

SET FOREIGN_KEY_CHECKS=0;

DROP TABLE IF EXISTS `admin`;

CREATE TABLE `admin` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '账户',

`auth_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,

`password_hash` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,

`password_reset_token` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,

`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,

`role` smallint(6) NOT NULL DEFAULT '10',

`mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '手机号码(登录账号)',

`status` smallint(6) NOT NULL DEFAULT '10' COMMENT '状态',

`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

`updated_at` datetime NOT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

INSERT INTO `admin` VALUES ('1', 'yicheng', 'kjfaoigk', '$2y$13$k0312JALBVCy7f2iPfJGXOdYUEYl6x8nSynSLpDNx6ky19gqZmCF2', '', '837269003@qq.com', '10', '15980893193', '10', '2017-09-28 16:08:31', '2017-09-19 16:08:28');

将上述 SQL文件进行执行,首先新建数据库

澳门新萄京 7

澳门新萄京 8

将数据库参数改为自己数据库名称

澳门新萄京 9

输入账户:yicheng  密码:123456 ,会报错 提示User表格不存在

澳门新萄京 10

如果我们把原来数据建立的admin 表格重命名 为user  刷新页面此时就没有报错了,显示登录成功

澳门新萄京 11

delete
在delete前执行

微服务可以在“自己的程序”中运行,并通过“轻量级设备与HTTP型API进行沟通”。关键在于该服务可以在自己的程序中运行。通过这一点我们就可以将服务公开与微服务架构(在现有系统中分布一个API)区分开来。在服务公开中,许多服务都可以被内部独立进程所限制。如果其中任何一个服务需要增加某种功能,那么就必须缩小进程范围。在微服务架构中,只需要在特定的某种服务中增加所需功能,而不影响整体进程。

1.在app/config/params.php中配置token参数

2:一般情况下User是留给前端普通用户注册使用的,怎样用自己的后台管理员Admin表格呢

将上一步的表格名称重新修改回admin,

在浏览器中访问:yii2.login/index.php?r=gii ,准备生成model

澳门新萄京 12

填好相关信息,框架会自动生成到文件目录

澳门新萄京 13

修改配置文件 设置用户登录验证类为上一步生成的admin模型

澳门新萄京 14

此时再次输入以yii2.login 发现依旧会报错,这又是为什么呢

澳门新萄京 15

是因为我们没有实现IdentityInterface接口

澳门新萄京 16

将原来的User 和model做一个比对,将Admin里面没有的函数从User表里面拷贝过来。

澳门新萄京 17

指定新的LoginForm: 拷贝一份LoginForm 修改它的命名空间,然后将Login 使用的Admin  as为User

澳门新萄京 18

SiteController 即我们默认的登录器 指定我们配置好的LoginForm

澳门新萄京 19

顺序清楚后,就来看下我写的一份日志操作类吧,第一版随便写写的,重复代码有点多,还未来得及优化。
View Code

实践微服务架构全方位的技术

return [ //微信接入 'wechat' =>[ 'token' => 'your token', ],];

使用前,需要引入数据库操作类,这是我之前写的一份,可参考《全新的PDO数据库操作类(仅适用Mysql)》。
  引入之后,就可以开始使用了。
  select
1

这仅仅是spring-cloud微服务框架的一个demo,可以完整运行。可能你初看到这里,会觉得这个项目目录太tm复杂了,确实,微服务要做的就是解耦、轻量化。这里面包含的组件和内容有:

2.在app/config/main.php中配置路由

$log
->insert(82,
'tb_member'
);

spring cloud eureka,服务注册和服务发现

因为接口模块使用的RESTful API,所以需要定义路由规则。

update
1
2
3

spring cloud config,动态配置项

'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ [ 'class' => 'yiirestUrlRule', 'controller' => 'wechat', 'extraPatterns' => [ 'GET valid' => 'valid', ], ], ],],

$log
->updateStart(82,
'tb_member'
);

ribbon,客户端负载均衡

3.在app/controllers中新建WechatController

//中间放更新操作代码

feign,

checkSignature($signature,$timestamp,$nonce)){ echo $echoStr; } } private function checkSignature($signature,$timestamp,$nonce) { // you must define TOKEN by yourself $token = Yii::$app->params['wechat']['token']; if  { echo 'TOKEN is not defined!'; } else { $tmpArr = array($token, $timestamp, $nonce); // use SORT_STRING rule sort; $tmpStr = implode; $tmpStr = sha1; if( $tmpStr == $signature ){ return true; }else{ return false; } } }}

$log
->updateEnd();

hystrix,熔断

在微信公众号后台配置URL和Token,然后提交验证即可。

delete
1

turbine

URL:http://app.demo.com/wechats/validToken:your token

$log
->
delete
(82,
'tb_member'
);

Spring Cloud Starters

二:获取用户信息

可以看到,一共只需要两个参数即可,分别是表ID(主键)和表名称。
  另外需要强调一点,表注释和字段注释一定要完整,因为记录的信息包含注释,目的就是为了查阅的时候能清楚哪个字段是干什么用的。
  下面就看下成品吧
[图片上传中。。。(1)]
[图片上传中。。。(2)]
  最后把表结构分享下,一共2张表,一张主表一张从表,主表记录操作表及操作人等信息,从表记录操作的表字段信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

同一个服务中的多数据库支持(AOP)

复制代码 代码如下:CREATE TABLE `wechat_user` NOT NULL, `openid` varchar COLLATE utf8_unicode_ci NOT NULL, `nickname` varchar COLLATE utf8_unicode_ci NOT NULL COMMENT '微信昵称', `sex` tinyint NOT NULL COMMENT '性别', `headimgurl` varchar COLLATE utf8_unicode_ci NOT NULL COMMENT '头像', `country` varchar COLLATE utf8_unicode_ci NOT NULL COMMENT '国家', `province` varchar COLLATE utf8_unicode_ci NOT NULL COMMENT '省份', `city` varchar COLLATE utf8_unicode_ci NOT NULL COMMENT '城市', `access_token` varchar COLLATE utf8_unicode_ci NOT NULL, `refresh_token` varchar COLLATE utf8_unicode_ci NOT NULL, `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;ALTER TABLE `wechat_user` ADD PRIMARY KEY ;


全链路traceId追踪

获取用户信息的相关接口

-- Table structure for tb_log

velocity 前端模板

1.用户授权接口:获取access_token、openId等;获取并保存用户资料到数据库


mybatis, pageHelper (分页), druid (连接池)

复制代码 代码如下:public function actionAccesstoken(){ $code = $_GET["code"]; $state = $_GET["state"]; $appid = Yii::$app->params['wechat']['appid']; $appsecret = Yii::$app->params['wechat']['appsecret']; $request_url = ''; //初始化一个curl会话 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec; $result = $this->response; //获取token和openid成功,数据解析 $access_token = $result['access_token']; $refresh_token = $result['refresh_token']; $openid = $result['openid']; //请求微信接口,获取用户信息 $userInfo = $this->getUserInfo($access_token,$openid); $user_check = WechatUser::find()->where->one { //更新用户资料 } else { //保存用户资料 } //前端网页的重定向 if { return $this->redirect; } else { return $this->redirect; }}

CREATE
TABLE
tb_log (

redis(序列化采用的是jdk默认序列化方案)

2.从微信获取用户资料

tbid
bigint
(20)
NOT
NULL
AUTO_INCREMENT,

slf4j & logback(及其配置)

复制代码 代码如下:public function getUserInfo($access_token,$openid){ $request_url = ''; //初始化一个curl会话 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec; $result = $this->response; return $result;}

adminid
bigint
(20)
DEFAULT
NULL
COMMENT
'管理员id'
,

国际化配置

public function actionUserinfo(){ if(isset{ $openid = $_REQUEST["openid"]; $user = WechatUser::find()->where->one { $result['error'] = 0; $result['msg'] = '获取成功'; $result['user'] = $user; } else { $result['error'] = 1; $result['msg'] = '没有该用户'; } } else { $result['error'] = 1; $result['msg'] = 'openid为空'; } return $result;}

type tinyint(4)
DEFAULT
'1'
COMMENT
'操作类型:1新增2修改3删除'
,

全局错误信息catch

三:微信支付

tableid
bigint
(20)
DEFAULT
NULL
,

线程池

1.微信支付接口:打包支付数据

tablename
varchar
(255)
COLLATE
utf8_unicode_ci
DEFAULT
NULL
COMMENT
'表名'
,

服务健康检查, 服务全链路健康检查

复制代码 代码如下:public function actionPay(){ if(isset&&isset&&isset($_REQUEST["totalFee"])){ //uid、oid、totalFee $uid = $_REQUEST["uid"]; $oid = $_REQUEST["oid"]; $totalFee = $_REQUEST["totalFee"]; $timestamp = time(); //微信支付参数 $appid = Yii::$app->params['wechat']['appid']; $mchid = Yii::$app->params['wechat']['mchid']; $key = Yii::$app->params['wechat']['key']; $notifyUrl = Yii::$app->params['wechat']['notifyUrl']; //支付打包 $wx_pay = new WechatPay; $package = $wx_pay->createJsBizPackage($uid, $totalFee, $oid, $notifyUrl, $timestamp); $result['error'] = 0; $result['msg'] = '支付打包成功'; $result['package'] = $package; return $result; }else{ $result['error'] = 1; $result['msg'] = '请求参数错误'; } return $result;}

comment
varchar
(255)
COLLATE
utf8_unicode_ci
DEFAULT
NULL
,

2.接收微信发送的异步支付结果通知

dt datetime
DEFAULT
NULL
,

代码的业务是:首先有一个登录页面,用户登录以后,能看到一个微博(moment)列表,同时也可以添加微博。在每个微博的最右边,可以看到每个微博的评论列表,也能添加评论。前端代码写的非常粗糙。。。 如果你真的运行了,求不吐槽。

复制代码 代码如下:public function actionNotify(){ $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); // if { die; } if ($postObj->return_code != 'SUCCESS') { die; } if ($postObj->result_code != 'SUCCESS') { die; } //微信支付参数 $appid = Yii::$app->params['wechat']['appid']; $mchid = Yii::$app->params['wechat']['mchid']; $key = Yii::$app->params['wechat']['key']; $wx_pay = new WechatPay; //验证签名 $arr = $postObj; unset; if ($wx_pay->getSign != $postObj->sign) { die; } //支付处理正确-判断是否已处理过支付状态 $orders = Order::find()->where(['uid'=>$postObj->openid, 'oid'=>$postObj->out_trade_no, 'status' => 0])->all > 0){ //更新订单状态 foreach { //更新订单 $order['status'] = 1; $order->update(); } return ''; } else { //订单状态已更新,直接返回 return ''; }}

PRIMARY
KEY
(tbid)

这里不谈根据业务的需求去选择是否微服务化,也不争辩什么时候该用什么样的框架,我这里只是把我们app后端的代码,抽象成一个代码库,希望能为你提供帮助。我们产品上线2个多月,后端基本没有出过问题(也跟量小有关系)。

3.微信支付类 WechatPay.php

) ENGINE=InnoDB AUTO_INCREMENT=27
DEFAULT
CHARSET=utf8
COLLATE
=utf8_unicode_ci;

运行

复制代码 代码如下:mchid = $mchid; $this->appid = $appid; $this->key = $key; } public function createJsBizPackage($openid, $totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp){ $config = array( 'mch_id' => $this->mchid, 'appid' => $this->appid, 'key' => $this->key, ); $unified = array( 'appid' => $config['appid'], 'attach' => '支付', 'body' => $orderName, 'mch_id' => $config['mch_id'], 'nonce_str' => self::createNonceStr(), 'notify_url' => $notifyUrl, 'openid' => $openid, 'out_trade_no' => $outTradeNo, 'spbill_create_ip' => '127.0.0.1', 'total_fee' => intval, 'trade_type' => 'JSAPI', ); $unified['sign'] = self::getSign($unified, $config['key']); $responseXml = self::curlPost('', self::arrayToXml; $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA); if ($unifiedOrder === false) { die; } if ($unifiedOrder->return_code != 'SUCCESS') { die($unifiedOrder->return_msg); } if ($unifiedOrder->result_code != 'SUCCESS') { die($unifiedOrder->err_code); } $arr = array( "appId" => $config['appid'], "timeStamp" => $timestamp, "nonceStr" => self::createNonceStr(), "package" => "prepay_signType" => 'MD5', ); $arr['paySign'] = self::getSign; return $arr; } public static function curlGet($url = '', $options = array{ $ch = curl_init; curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); if { curl_setopt_array; } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec; return $data; } public static function curlPost($url = '', $postData = '', $options = array{ if { $postData = http_build_query; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt; curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数 if { curl_setopt_array; } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec; return $data; } public static function createNonceStr{ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i = 0; $i"; foreach { if { $xml .= "" . $val . "" . $key . ">"; } else { $xml .= "" . $key . ">"; } } $xml .= ""; return $xml; } public static function getSign{ ksort; $unSignParaString = self::formatQueryParaMap; $signStr = strtoupper(md5($unSignParaString . "&key=" . $key)); return $signStr; } protected static function formatQueryParaMap($paraMap, $urlEncode = false){ $buff = ""; ksort; foreach { if (null != $v && "null" != $v) { if { $v = urlencode; } $buff .= $k . "=" . $v . "&"; } } $reqPar = ''; if { $reqPar = substr($buff, 0, strlen; } return $reqPar; }}


首先,你在本地需要有一个redis和mysql,redis默认启动就可以。数据库表的创建语句见下:

四:获取JS-SDK的config参数

-- Table structure for tb_log_content

create database test;

根据微信公众平台开发者文档:


CREATE TABLE `account` (

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

CREATE
TABLE
tb_log_content (

`user_id` varchar(127) NOT NULL DEFAULT '',

复制代码 代码如下:wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2});

tbid
bigint
(20)
NOT
NULL
AUTO_INCREMENT,

`user_name` varchar(127) NOT NULL DEFAULT '',

1.微信支付类 WechatPay.php

logid
bigint
(20)
DEFAULT
NULL
,

`password` varchar(127) NOT NULL DEFAULT '',

复制代码 代码如下: $this->appid, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signPackage; } public static function getJsApiTicket() { //使用Redis缓存 jsapi_ticket $redis = Yii::$app->redis; $redis_ticket = $redis->get('wechat:jsapi_ticket'); if { $ticket = $redis_ticket; } else { $accessToken = self::getAccessToken(); $url = "; $res = json_decode; $ticket = $res->ticket; if { $redis->set('wechat:jsapi_ticket', $ticket); $redis->expire('wechat:jsapi_ticket', 7000); } } return $ticket; } public static function getAccessToken() { //使用Redis缓存 access_token $redis = Yii::$app->redis; $redis_token = $redis->get('wechat:access_token'); if { $access_token = $redis_token; } else { $appid = Yii::$app->params['wechat']['appid']; $appsecret = Yii::$app->params['wechat']['appsecret']; $url = "; $res = json_decode; $access_token = $res->access_token; if { $redis->set('wechat:access_token', $access_token); $redis->expire('wechat:access_token', 7000); } } return $access_token; } public static function curlGet($url = '', $options = array{ $ch = curl_init; curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); if { curl_setopt_array; } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec; return $data; } public static function curlPost($url = '', $postData = '', $options = array{ if { $postData = http_build_query; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt; curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数 if { curl_setopt_array; } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec; return $data; } public static function createNonceStr{ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i = 0; $i

tbkey longtext
COLLATE
utf8_unicode_ci,

`gmt_created` datetime NOT NULL,

2.获取config参数接口

tbvalue longtext
COLLATE
utf8_unicode_ci,

`gmt_modified` datetime DEFAULT NULL,

public function actionConfig(){ if (isset { $url = $_REQUEST['url']; //微信支付参数 $appid = Yii::$app->params['wechat']['appid']; $mchid = Yii::$app->params['wechat']['mchid']; $key = Yii::$app->params['wechat']['key']; $wx_pay = new WechatPay; $package = $wx_pay->getSignPackage; $result['error'] = 0; $result['msg'] = '获取成功'; $result['config'] = $package; } else { $result['error'] = 1; $result['msg'] = '参数错误'; } return $result;}

currenttbvalue longtext
COLLATE
utf8_unicode_ci,

`is_deleted` tinyint(1) NOT NULL DEFAULT '0',

以上就是利用Yii2微信后台开发全部过程及示例代码,希望本文对大家基于php的微信公众平台开发有所帮助。

comment
varchar
(255)
COLLATE
utf8_unicode_ci
DEFAULT
NULL
,

PRIMARY KEY (`user_id`),

PRIMARY
KEY
(tbid)

KEY `index_user_id` (`user_id`) KEY_BLOCK_SIZE=10

) ENGINE=InnoDB AUTO_INCREMENT=109
DEFAULT
CHARSET=utf8
COLLATE
=utf8_unicode_ci;

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `moment` (

`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,

`user_id` varchar(127) COLLATE utf8mb4_澳门新萄京:完美利用Yii2微信后台开发的系列总结_php技巧_脚本之家,高级架构师教你如何实践微服务架构全方位的技术。unicode_ci NOT NULL,

`content` text COLLATE utf8mb4_unicode_ci,

`gmt_created` datetime NOT NULL,

`gmt_modified` datetime DEFAULT NULL,

`is_deleted` tinyint(1) DEFAULT '0',

PRIMARY KEY (`id`),

KEY `index_user_id` (`user_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

create database test2;

CREATE TABLE `comment` (

`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,

`moment_id` bigint(20) unsigned NOT NULL,

`content` text COLLATE utf8mb4_unicode_ci,

`gmt_created` datetime NOT NULL,

`gmt_modified` datetime DEFAULT NULL,

`is_deleted` tinyint(1) DEFAULT '0',

PRIMARY KEY (`id`),

KEY `index_moment_id` (`moment_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

系统环境需要Java 8 和 maven 3及以上

运行命令如下 (需要按顺序运行每个模块):

cd spring-cloud-parent

mvn clean install -DskipTests

cd ../spring-cloud-client

mvn clean install -DskipTests

cd ../spring-cloud-starter

mvn clean install -DskipTests

cd spring-cloud-eureka

mvn clean spring-boot:run

cd spring-cloud-account

mvn clean spring-boot:run

cd spring-cloud-biz

mvn clean spring-boot:run

cd spring-cloud-gateway

mvn clean spring-boot:run

浏览器中打开

代码解释

代码中的依赖关系见下图:

澳门新萄京 20

spring-cloud-parent

是一个空的mvn project, 包含了一些被其他项目所需要的公共的依赖。我这里创建parent,仅仅是因为我不想把很多相同的依赖在spring-cloud-eureka、spring-cloud-biz、spring-cloud-account和spring-cloud-gateway这几个项目中重复写一遍,所以,一般微服务project都集成spring-cloud-parent。嗯,懒惰是人类的第一生产力。

spring-cloud-starter

是一个我创建的spring starter, 里面包含的是一些公共的bean,和一些公共的bean配置,比如国际化locle配置、缓存CacheService配置,messageConvertor配置等,spring-cloud-biz、spring-cloud-account和spring-cloud-gateway等微服务都需要依赖和共用这些基础配置。

spring-cloud-client

是一个公共依赖,这里包含的是一个util类,以及多个模块需要共同使用的、和数据库表对应的Java model.

spring-cloud-eureka

是一个服务注册和服务发现中心,需要集群化。代码里,我把spring-cloud-config动态配置项也集成在这里面了。服务发现的心跳检测时间,也从15s改到了5s,这对于快速发现节点故障很有作用。

spring-cloud-account

是整个工程的账号服务模块。对于一个大型的系统来讲,单独的账号服务系统是很有必要解耦出来的。

spring-cloud-biz

是实际的业务模块,包括发微博模块和评论模块。整个代码中动态使用了两个数据库,我这里对数据库的切分只是简单从业务上切分,既:微博在一个库中,评论在另外一个库中,同时写了一个@TargetDataSource注解,方便动态切换数据库。其实对于分库、分表、读写分离,代码都是类似的。

spring-cloud-gateway

是整个系统的网关服务,所有来自端上的请求,包括app或者web页面,都需要先到网关,由网关做过处理之后再转发给其他服务。比如,网关需要处理登录状态问题,需要处理上传文件问题,需要做一些过滤,以及其他多种切面上的事情。

总结

以 上就是我对Java大型互联网-高级架构师教你如何实践微服务架构全方位的技术问题 及其优化总结,分享给大家,希望大家知道什么是Java大型互联网-高级架构师教你如何实践微服务架构全方位的技术问题及其优化。觉得收获的话可以点个关注收藏转发一波喔,谢谢大佬们支持!

1、多写多敲代码,好的代码与扎实的基础知识一定是实践出来的

2、可以去百度搜索腾讯课堂图灵学院的视频来学习一下java架构实战案例,还挺不错的。

最后,每一位读到这里的网友,感谢你们能耐心地看完。希望在成为一名更优秀的Java程序员的道路上,我们可以一起学习、一起进步。

3丶想了解学习以上课程内容可加群:569068099验证码:简书(06 必过)

本文由澳门新萄京发布于澳门新萄京最大平台,转载请注明出处:澳门新萄京:完美利用Yii2微信后台开发的系列总

上一篇:澳门新萄京:学学笔记8,实践上下文详细图解 下一篇:没有了
猜你喜欢
热门排行
精彩图文