方便要开发微信公众号的朋友们,可以快速将服务搭建起来,不要把时间浪费在服务的搭建上,专心写我们的业务代码。
你需要了解的知识:
1.微信公众号大概的开发流程
2.注册公众号(本脚手架是用公共的测试账号)
3.服务器的配置
4.内网穿透(我用的是花生壳)
5.公众号开发文档先大概看一遍
废话不多说了,你懂得,直接讲重点…
本项目依赖SDK开发工具包(WxJava)https://gitee.com/binary/weixin-java-tools
开发者ID(AppID)
开发者密码(AppSecret)
服务器地址(URL)
令牌(Token)
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时(7200秒),需定时刷新,重复获取将导致上次获取的access_token失效。
将以上问题先注意一下。
1.application.xml (公众号对应配置修改,支持多个公众号)
2.JedisConfiguration.java (修改Redis配置,如果不配置,就内存缓存)
我的内网穿透域名:http://chenxingxing.51vip.biz
1.接口配置信息URL:${内网穿透域名}/wx/portal/${appId}
例如:http://chenxingxing.51vip.biz/wx/portal/wx62458041039e62ee
2.JS接口安全域名
例如:chenxingxing.51vip.biz
3.消息模板
例如:{{first.DATA}}
4.创建菜单
例如:http://chenxingxing.51vip.biz/wx/menu/wx62458041039e62ee/create
5.发送模板
例如:http://chenxingxing.51vip.biz/wx/other/wx62458041039e62ee/sendTemplate
6.授权回调地址
例如:http://chenxingxing.51vip.biz/wx/redirect/wx62458041039e62ee/oauth/callback
7.拆分链接
例如:http://chenxingxing.51vip.biz/wx/redirect/wx62458041039e62ee/split/jump?url=http://chenxingxing.51vip.biz
基本上到这,你的公众号就可以用了。然后你配置一下菜单,发消息,发模板,测试测试。
公众号开发文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
访问url:http://chenxingxing.51vip.biz/wx/menu/wx62458041039e62ee/create
访问url:http://chenxingxing.51vip.biz/wx/other/wx62458041039e62ee/sendTemplate
访问url:http://chenxingxing.51vip.biz/jssdk
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Jssdk测试title>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js">script>
<script type="text/javascript" src="https://www.w3school.com.cn/jquery/jquery-1.11.1.min.js">script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="https://cdn.bootcss.com/weui/1.1.3/style/weui.min.css">
<link rel="stylesheet" href="https://cdn.bootcss.com/jquery-weui/1.2.1/css/jquery-weui.min.css">
head>
<body style="text-align: center;">
<h1>Jssdk测试h1>
<br>
<a href="javascript:;" class="weui-btn weui-btn_primary" onclick="wxConfig()">wxConfiga>
<a href="javascript:;" class="weui-btn weui-btn_warn" onclick="share()">分享a>
<a href="javascript:;" class="weui-btn weui-btn_default" onclick="chooseImage()">拍照a>
<a href="javascript:;" class="weui-btn weui-btn_warn" onclick="pay()">微信支付a>
<a href="javascript:;" class="weui-btn weui-btn_plain-default" onclick="getLocation()">获取地理位置a>
<a href="javascript:;" class="weui-btn weui-btn_plain-primary" onclick="scanQRCode()">扫一扫a>
body>
<script src="https://cdn.bootcss.com/jquery/1.11.0/jquery.min.js">script>
<script src="https://cdn.bootcss.com/jquery-weui/1.2.1/js/jquery-weui.min.js">script>
<script>
function wxConfig() {
$.post("wx/redirect/wx62458041039e62ee/create/jsapi_sign",{
url:location.href //传递当前页面的url
},function(data){
wx.config({
debug: true,// 开启调试模式,如何设计为true的话调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印,如果为false则不打印
appId: data.appId,// 必填,公众号的唯一标识
timestamp: data.timestamp,// 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature,// 必填,签名
jsApiList: ['chooseImage', 'scanQRCode','updateAppMessageShareData','getLocation','closeWindow','checkJsApi'] // 必填,需要使用的JS接口列表
});
wx.ready(function(){
$.alert("验证成功");
});
wx.error(function(res){
$.alert("微信认证失败,请重试");
});
});
}
function share() {
wx.updateAppMessageShareData({
title: '分享标题', // 分享标题
desc: '分享描述', // 分享描述
link: 'http://chenxingxing.51vip.biz/jssdk', // 该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'http://mmbiz.qpic.cn/mmbiz_jpg/kqu5eakDVMTcnKRKc54W9NZaLkWLSlibgXOAvicicAGV6XwTSYf6WhMQ1ov0RLE9ahKw54BvOcmexNmy9pdNGklqw/0', // 分享图标
success: function (res) {
// 设置成功
$.alert(res.toString());
}
})
}
function chooseImage() {
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
$.alert(localIds);
}
});
}
function getLocation() {
wx.getLocation({
type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
success: function (res) {
var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
var speed = res.speed; // 速度,以米/每秒计
var accuracy = res.accuracy; // 位置精度
$.alert(res.toString());
}
});
}
function scanQRCode() {
wx.scanQRCode({
needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
$.alert(res.toString());
}
});
}
function pay() {
wx.chooseWXPay({
timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: '', // 支付签名随机串,不长于 32 位
package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: '', // 支付签名
success: function (res) {
// 支付成功后的回调函数
}
});
}
script>
html>
访问url:http://chenxingxing.51vip.biz/wx/redirect/wx62458041039e62ee/split/jump?url=http://chenxingxing.51vip.biz
比如我们现在微信公众号里面访问http://chenxingxing.51vip.biz这个页面,但是这个页面要先让用户授权,所以这里我们同样通过拆分链接的方式,在后头自动实现授权,然后将用户授权完的信息token,返回给前端。【拆分链接的好处,不需要配置个性化参数,很多地方都可以嵌入该链接】
package com.lxh.mp.config;
import com.lxh.mp.handler.*;
import lombok.Data;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
import static me.chanjar.weixin.common.api.WxConsts.EventType.*;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType.CLICK;
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType.VIEW;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
/**
* created by [email protected] on 2020/2/21
* 微信公众号配置
* wxMpService
* WxMpMessageRouter
*
*/
@Configuration
@Data
@EnableConfigurationProperties(WxMpProperties.class)
@Order(1)
public class WxMpConfiguration {
private final WxMpProperties properties;
// 更新2020.2.22 加入redis
@Resource
private JedisPool jedisPool;
private final LogHandler logHandler;
private final NullHandler nullHandler;
private final KfSessionHandler kfSessionHandler;
private final StoreCheckNotifyHandler storeCheckNotifyHandler;
private final LocationHandler locationHandler;
private final MenuHandler menuHandler;
private final MsgHandler msgHandler;
private final UnSubscribeHandler unsubscribeHandler;
private final SubscribeHandler subscribeHandler;
private final ScanHandler scanHandler;
@Bean
public WxMpService wxMpService() {
final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
if (configs == null) {
throw new RuntimeException("请添加公众号相关配置,注意别配错了!");
}
WxMpService service = new WxMpServiceImpl();
// 公众号信息缓存起来
service.setMultiConfigStorages(configs.stream().map(a -> {
// 默认缓存在内存中,配置redis就放入redis中
WxMpDefaultConfigImpl configStorage = !redisIsOk() ? new WxMpDefaultConfigImpl() : new WxMpRedisConfigImpl(jedisPool);
configStorage.setAppId(a.getAppId());
configStorage.setSecret(a.getSecret());
configStorage.setToken(a.getToken());
configStorage.setAesKey(a.getAesKey());
return configStorage;
}).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, e -> e, (o, n) -> o)));
return service;
}
/**
* redis是否可用
* @return
*/
private boolean redisIsOk(){
try {
Jedis jedis = jedisPool.getResource();
jedis.ping();
return true;
}catch (Exception e){
e.printStackTrace();
return false;
}
}
@Bean
public WxMpMessageRouter wxMpMessageRouter(WxMpService wxMpService) {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
// 记录所有事件的日志 (异步执行)
newRouter.rule().handler(this.logHandler).next();
/**--------------------------------------- 事件处理 ----------------------------------------**/
// 接收客服会话管理事件
newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION).handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION).handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION).handler(this.kfSessionHandler).end();
// 门店审核事件
newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();
// 自定义菜单事件
newRouter.rule().async(false).msgType(EVENT).event(CLICK).handler(this.menuHandler).end();
// 点击菜单连接事件
newRouter.rule().async(false).msgType(EVENT).event(VIEW).handler(this.nullHandler).end();
// 关注事件
newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
// 取消关注事件
newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
// 上报地理位置事件
newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.LOCATION).handler(this.locationHandler).end();
// 接收地理位置消息
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(this.locationHandler).end();
// 扫码事件
newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.SCAN).handler(this.scanHandler).end();
// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();
return newRouter;
}
}
后续还将整理小程序,企业微信的脚手架!!!