EasyWeChat使用(laravel框架下)
- 最近做了个项目是关于微信网页开发的,今天记录下在做项目中的关于微信这块遇到的一些坑
- 关于微信这块,用的是EasyWeChat,提高了开发的效率.在看EasyWeChat这个文档的时候发现了有专门针对laravel 框架的包,所以就用了laravel-wechat
首先是安装这个composer包
composer require "overtrue/laravel-wechat:~3.0"
接着注册ServiceProvider,由于看github文档说明时,文档上有错误LaravelWeChat写成了小写Laravelwechat 在phpstorm中按ctr点击鼠标也能跳转方法,但是在运行项目的时候报找不到这个类,最后看了github上的issue有人遇到同样的问题,发现了这个大小写问题,此为第一个坑.
Overtrue\LaravelWeChat\ServiceProvider::class
- 接着是token验证,该配置的地方都没问题了,但是这个token验证老师失败,最后发现由于laravel 自带的CSRF 中间件要排除路由,和这个中间件平级,同时CSRF排除这个url
Route::any('/wechat', 'WeChatController@serve');
Route::group(['middleware' => 'web'], funcation(){})
过滤url
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
//
'wechat', 'web/pay/callback', 'web/pay/signCallback'
];
}
- 关注回复相关代码
namespace App\Http\Controllers;
use App\Http\Controllers\Web\Controller;
use Illuminate\Http\Request;
use App\Http\Controllers\Web\UserController as User;
use App\Models\Setting;
use App\Models\WechatReply;
use EasyWeChat\Message\News;
class WechatController extends Controller
{
public function serve()
{
$app = app('wechat');
$app->server->setMessageHandler(function($message) use ($app){
if ($message->MsgType=='event') {
$userOpenid = $message->FromUserName;
switch ($message->Event) {
case 'subscribe':
$userInfo['openid'] = $userOpenid;
$userService = $app->user; //获取用户服务
$user = $userService->get($userInfo['openid']);
$userInfo['nickname'] = $user['nickname'];
$userInfo['headimgurl'] = $user['headimgurl'];
if (userAttention($userInfo)) {
return $this->reply('follow_keyword');
}else{
return '您的信息由于某种原因没有保存,请重新关注';
}
break;
case 'unsubscribe':
if (userCancelAttention($userOpenid)) {
return '已取消关注';
}
break;
default:
# code...
break;
}
} elseif ($message->MsgType=='text') { //关键字回复
$replay = WechatReply::where('keyword', $message->Content)->first();
if ($replay) {
} else {
}
}
});
return $app->server->serve();
}
- 网页授权,EasyWeChat进行网页授权非常简单,这个项目中,我主要用了静默授权,只要将路由包含在这个中间件中,通过session就可以获得这个用户的openid
Route::group(['middleware' => 'wechat.oauth'], function () {
});
$user = session('wechat.oauth_user
$openid = $user['id'];
- 菜单的设置 ,通过注入的方式获得菜单的实例
use EasyWeChat\Foundation\Application;
use Illuminate\Http\Request;
class MenuController extends Controller
{
public $menu;
public function __construct(Application $app)
{
$this->menu = $app->menu;
}
public function create()
{
//这里进行菜单数组格式的组装
$this->menu->add($buttons);
}
- 模板消息 ,写一个全局辅助函数,来发送模板消息,获得模板消息应用实例
function sendTemplateMsg($templateId, $userId, $data, $url)
{
$user = \App\Models\User::where('id', $userId)->first();
$app = new \EasyWeChat\Foundation\Application(config('wechat'));
$notice = $app->notice;
$result = $notice->uses($templateId)->withUrl($url)->andData($data)->andReceiver($user->openid)->send();
return $result;
}
- 支付,支付这边用的是jssdk方式支付,最主要的是要获得统一下单的prepay_id.
前端页面这个$js要在控制器传到这个待支付界面
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript" charset="utf-8"></script> //微信的js库文件
wx.config(<?php echo $js->config(array('chooseWXPay'), false) ?>);
点击支付调用此方法
function pay() {
$.ajax({
url: siteUrl + '/web/pay/create',
type: 'get',
dataType: 'json',
data: {
'id': "{{ $order->id }}",// 订单ID
'coupon_id': "{{ $coupon_id }}",// 优惠券ID
'actual_payment_amount': deposit // 实际支付金额
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function (data) {
if (data['code'] === 0) {
data = data['data'];
wx.ready(function() {
wx.chooseWXPay({
timestamp: data['timestamp'],
nonceStr: data['nonceStr'],
package: data['package'],
signType: data['signType'],
paySign: data['paySign'],
success: function (res) {
// 支付成功跳转新页面
window.location.href = siteUrl + "/web/order/paySuccess";
}
});
});
} else {
// 统一下单失败
alert(data['data']['err_code_des']);
}
}
});
}
create方法代码
use EasyWeChat\Foundation\Application;
use EasyWeChat\Payment\Order as WechatOrder;
use Illuminate\Support\Facades\Log;
class PayController extends Controller
{
private $app;
public function __construct()
{
$this->app = new Application(config('wechat'));
}
// 微信统一下单
public function createOrder(Request $request)
{
$order = Order::find($request->id);
$attributes = [
'trade_type' => 'JSAPI',
'body' => '',
'detail' => '订单号: ' . $order->order_no,
'out_trade_no' => $order->order_no,
'total_fee' => $request->actual_payment_amount * 100, // 单位:分
'openid' => getOpenId(), // trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识,
'notify_url' => url('/web/pay/callback'), //支付回调方法
'attach' => '' //这里是带给回调方法的一些字段,用于业务逻辑处理
];
$order = new WechatOrder($attributes);
$result = $this->app->payment->prepare($order);
if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
$prepayId = $result->prepay_id;
$config = $this->app->payment->configForJSSDKPayment($prepayId); // 返回数组
return apiReturn(SUCCESS, '统一下单成功', $config);
}
return apiReturn(ERROR, '统一下单失败', $result);
}
由于callback方法也是post类型所以在CSRF中间件中也要过滤,这也是有的人发现支付完了,但是没有调用callback方法
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
'wechat', 'web/pay/callback'
];
}
callback方法
// 微信支付回调
public function callback(Request $request)
{
$response = $this->app->payment->handleNotify(function($notify, $successful) {
// 记录日志
Log::info('微信支付: ' . json_encode($notify));
// 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
$order = Order::where('order_no', $notify->out_trade_no)->first();
// 检查订单是否已经更新过支付状态
if ($order->pay_time) {
return true;
}
// 用户是否支付成功
if ($successful) {
//业务逻辑代码,处理
$attach = json_decode($notify->attach);
apiReturn(SUCCESS, '支付成功', $notify);
} else {
apiReturn(SUCCESS, '支付失败', $notify);
}
$order->save(); // 保存订单
$this->sendPayMessage($order->id);
return true; // 返回处理完成
});
return $response;
}
- 分享朋友,分享朋友圈,本来以为点击页面中的某一个按钮能直接分享给朋友呢,其实不是的,要使用微信的发送朋友,使用jssdk可以自定义分享的地址
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript" charset="utf-8"></script>
wx.config(<?php echo $js->config(array('onMenuShareTimeline', 'onMenuShareAppMessage'), false) ?>);
wx.ready(function() {
wx.onMenuShareAppMessage({
title: '', // 分享标题
desc: '', // 分享描述
link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
type: 'link', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
alert('分享成功');
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
},
fail: function () {
alert('fail');
}
});
wx.onMenuShareTimeline({
title: '推荐拿红包', // 分享标题
link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
alert('分享成功')
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert('请重新分享')
}
});
});
起初我没有用wx.ready包住这两段代码,结果是分享的是我当前界面,而不是自定义的url地址,但是微信开发文档写的是:
- wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
我理解的是分享也是手动触发的应该也不需要放在ready中, 但是实际不行.
EasyWeChat使用(laravel框架下)的更多相关文章
- Laravel框架下容器Container 的依赖注入和反射应用
依赖注入,简单说是把类里头依赖的对象,置于类外头,即客户端调用处.相当于把类与类解耦. 一个简单的例子: class A { public function __construct() { // 这种 ...
- 基于Laravel框架下使用守护进程supervisor实现定时任务(毫秒)
本篇文章给大家带来的内容是关于基于Laravel框架下使用守护进程supervisor实现定时任务(毫秒),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 公司需要实现X分钟内每隔Y秒 ...
- Laravel框架下路由的使用(源码解析)
本篇文章给大家带来的内容是关于Laravel框架下路由的使用(源码解析),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 前言 我的解析文章并非深层次多领域的解析攻略.但是参考着开发文 ...
- 装饰器模式以及Laravel框架下的中间件应用
Laravel框架的中间件使用:从请求进来到响应返回,经过中间件的层层包装,这种场景很适合用到一种设计模式---装饰器模式. 装饰器模式的作用,多种外界因素改变对象的行为.使用继承的方式改变行为不太被 ...
- 解析Laravel框架下的Contracts契约
Contracts Laravel 的契约是一组定义框架提供的核心服务的接口, 例如我们在介绍用户认证的章节中到的用户看守器契约IllumninateContractsAuthGuard 和用户提供器 ...
- laravel 框架 下拉分页
<!doctype html><html lang="en"><head> <meta charset="UTF-8" ...
- laravel框架中所用到的依赖注入
用Laravel开发前前后后有2个月左右了,之前一直写Java,就像找到Java和PHP之前的共同点,用Java的某些原理去理解PHP会发现还是有很多共通之处的.Java的依赖注入已经是一个很常见的概 ...
- Laravel框架使用融云服务端SDK
方法一: 使用第三方依赖安装(在项目根目录) 第一步:安装 composer require latrell/rongcloud dev-master 第二步:更新依赖包 c ...
- nginx下laravel框架rewrite的设置
nginx下laravel框架rewrite的设置 百牛信息技术bainiu.ltd整理发布于博客园 在nginx的vhost站点配置文件中加入以下内容即可 1 2 3 4 5 6 7 8 9 10 ...
随机推荐
- LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分
题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...
- 服务容错和Hystrix
一.雪崩效应 在微服务架构中,通常有多个服务层调用,如果某个服务不可用,造成调用的服务也不可用,造成整个系统不可用的情况,叫做雪崩效应 二.Hystrix 放雪崩利器Hystrix,基于Netflix ...
- Excel技巧--实现交叉查询
如上图,要实现某个地区和某个产品的销售额查询显示.可以使用Match和Index函数的使用来实现: 1.产品名称和城市栏,制作成列表可选:使用“数据”-->“数据验证”的方法. 2.先在旁边空位 ...
- UE4:四种加载资源的方式
转自:https://blog.csdn.net/zhangxsv123/article/details/79707686 第一种: 如果该蓝图有C++类(或者说是从C++类创建的蓝图),直接进行加载 ...
- IDEA查看类继承关系及生成类关系图
1.在想要查看的类上按 Ctrl + H -> Diagrams -> Show Diagrams -> Java Class Diagrams -> Show Impleme ...
- 汉化-PowerDesigner 16.5 汉化
转载: https://www.cnblogs.com/yeaicc/p/PowerDesigner16CN.html 一.背景 经常使用PowerDesigner,之前使用15版本,后来16出来后, ...
- 保持ssh连接长时间不断开的技巧
我经常用ssh连接服务器,过段时间不用, 需要恢复一下断开的连接, 原因是NAT防火墙喜欢对空闲的会话进行超时处理,以确保它们状态表的干净和内存的低占用率,因为 长时间保持连接, 会长期占用部分系统资 ...
- HBuilder ,及自用主题
字体:Consolas http://bbs.csdn.net/topics/390858585 让代码更美:你最爱的编程字体 http://www.dcloud.io HBuilder下载 htt ...
- OpenCV代码:画出轮廓的外接矩形,和中心点
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include & ...
- tomcat 8 在线管理admin配置
在tomcat8下,更加注重安全性.如果要使用在管理控制台部署应用,需要修改更多的配置. 在$tomcat_base$/webapps/manager/META-INF/context.xml中 添加 ...