赞
踩
文末附源码,或可先将依赖复制到自己的项目,内容参考郑清的博客-CSDN博客
想要进行微信相关的开发,首先是要弄明白几个概念,明确自己要干什么:
(1)微信公众平台和微信开放平台
开放平台:https://open.weixin.qq.com;公众平台:https://mp.weixin.qq.com
我们可以分别看一两者的官网,首先看开放平台
微信开放平台就是微信把自家的服务给其他人使用。比如你的网站要做网页授权登陆,就需要来到开放平台,在开放平台中将你的网站注册到其中;再比如想要自己开发的手机app实现微信分享、收藏,使用微信支付,也是需要到开放平台。这里的重点是你的应用要使用微信的服务。
其实在开放平台中也包含公众平台的入口,那就是其中的公众账号开发,点进去就会进入公众平台,公众平台官网如下:
公众平台要做的事是让所有人(普通人和开发者)更好的使用微信自己的产品,即服务号、订阅号、小程序、企业微信。所谓更好的使用就是帮助我们使用使用它们,让他们符合我们的需求,比如对于普通人,想使订阅号发布内容、设置自动回复等。比如对于开发者想使用公众号更有个性化的内容回复、进行网页授权等,网页授权也就是在公众号内打开网页,在网页中可以获取微信用户的信息,这与上边提到的第三方应用微信授权登录是不一样的,公众号内的授权只能在微信客户端中使用。但其实本质上差不多,都是去获取微信用户的信息。
这里可以知道,使用订阅号、服务号、企业微信、小程序实现个性化业务就要到公众平台。这里的重点是你要直接使用微信的产品。
(2)公众号
公众号是一个统称,通常我们说的就是订阅号和服务号,订阅月就是我们微信中放在一起的公众号,服务号就是那些单独的、在聊天页面的公众号。但是还包括微信小程序和企业微信,比如想使用企业微信管理员工、进行小程序开发。
(3)appID、appsecret、openID、unionID(来自微微信开放文档 )
ID名称 | 说明 |
---|---|
AppID | - AppID是不同类型的产品的帐号ID,是帐号的唯一标识符。 - 例如公众号的AppID、小程序的AppID、开放平台的AppID、第三方平台的AppID、移动应用的AppID、网站应用的AppID、小商店的AppID等等。 |
openid | - openid是微信用户在不同类型的产品的身份ID。 - 微信用户访问公众号、小程序、移动应用、网站应用、小商店等都会有唯一的openid,但同一个微信用户访问不同的产品生成的openid也是不一样的。 - 例如,对于不同公众号,同一用户的openid不同;同理,对于不同的小程序,同一用户的openid也是不同的 |
unionid | - unionid是微信用户在同一个开放平台下的产品的身份ID。 - 如果开发者拥有多个移动应用、网站应用、和公众帐号(即公众号和小程序),可通过 UnionID 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的 UnionID 是唯一的。即,同一用户,对同一个微信开放平台下的不同应用,UnionID是相同的。 |
(4)code、access_token:
access_token是微信接口调用凭证,微信如何给我们提供功能和服务呢?自然是通过接口,微信的接口调用需要凭证,那就是access_token
code:在某些场景下,主要是用户认证授权,如何确保用户真的授权了,那就是code,用户点了同意授权就会得到一个code,通过这个code就可以获取access_token,从而使用微信接口。
微信公众号有两种开发模式:(图片来自微信公众号开发 (1) 微信接入认证成为开发者)
这位老哥的图里已经说的很清楚了。其实就是两种公众,普通人和开发者如何更好的使用公众号的两种模式。
既然是微信公众号的开发,那么自然我们要讨论的是第二种模式了。
3、开发前准备工作
(1)获取一个公众号
测试公众号申请地址https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
既然要做公众号的开发,自然首先需要有一个公众号了,当然如果嫌注册麻烦,或者已有公众号但是不能使用,也可申请一个测试公众号,随便折腾,如下图所示:
(2)将你自己电脑的80端口映射出去
也就说做内网穿透,让微信服务可以访问你电脑的服务。这里推荐使用ngrok (ngrok.cc),关于ngrok使用很简单,注册登录之后选择隧道管理–开通隧道,免费的就行,但是需要2元钱的实名认证费用。填写配置,开通就行了,注意一定得是80端口。
然后下载客户端,根据文档使用命令启动就行,启动后我们接可以看到如下界面:
在外网访问http://iwat.free.idcfengye.com就会请求到本机的80端口。
对微信公众号开发又了一定的了解,做好了准备工作之后,就开始写代码了。这里我们使用java进行演示,创建spring-boot项目。
根据上边的图我们知道,我们需要搭建一个自己的服务器,然后我们在自己的服务中通过微信服务器给用户发消息等,同时用户也是通过微信服务器请求我们服务器的服务,所以首先就要让微信认识我们的服务器,同时可以访问到我们的服务(所以要把80映射出去)。认证成为开发者这一步要做的就是让我们的服务和微信服务器相互认识。
(1)创建springboot项目,新建一个controller
添加如下代码:
@RestController @RequestMapping("/api/weixin/index") @Api(tags = "微信 - 接口") public class IndexController { // TODO 这里的token是微信公众平台上自己所配的! private static final String token = "zhengqing"; @Autowired private MsgService msgService; /** * 处理微信认证:验证服务器地址的有效性,get提交 * signature: 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 * timestamp 时间戳 * nonce: 随机数 * echostr: 随机字符串 */ @GetMapping public void checkSignature(HttpServletRequest request, HttpServletResponse response) throws IOException { System.out.println("============= 处理微信认证 ==============="); // 拿到微信的请求参数 String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); // ① 将token、timestamp、nonce三个参数进行字典序排序 b a d c h ==>a b c d h String[] strArr = {token, timestamp, nonce}; // 字典排序 Arrays.sort(strArr); // ② 将三个参数字符串拼接成一个字符串进行sha1加密 StringBuffer sb = new StringBuffer(); // 字符串拼接 for (String str : strArr) { sb.append(str); } // 加密 String sha1Str = SecurityUtil.sha1(sb.toString()); // ③ 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 if (sha1Str.equals(signature)) { // 如果相等,就是来自微信请求 // 若确认此次GET请求来自微信服务器,原样返回echostr参数内容,则接入生效 response.getWriter().println(echostr); } } }
SecurityUtil代码
public class SecurityUtil { public static String sha1(String str) { try { StringBuilder sb = new StringBuilder(); MessageDigest digest = MessageDigest.getInstance("sha1"); // 放入加密字符串 digest.update(str.getBytes()); // 进行加密 byte[] digestMsg = digest.digest(); // byte转换16进制 for (byte b : digestMsg) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return str; } }
(2)配置端口号
(3)启动项目
(4)在测试号页面填写公众号配置信息
提交,显示配置成功就可以了。
有了测试公众号,点击关注以后进入发现,里面没有任何菜单。公众号的菜单可以在公众平台直接设置,也可以通过在我们的服务中调用微信的接口去设置。
(1)第一步要看一下微信自定义菜单的文档:微信开放文档-自定义菜单 (qq.com)
(2)第二步我们可以先在微信公众平台接口调试工具 (qq.com) 中使用接口感受一下
首选获取access_token
然后设置菜单:
菜单项(注意微信文档中的测试菜单包含了小程序url,需要删除)
{ "button":[ { "type":"click", "name":"今日歌曲", "key":"V1001_TODAY_MUSIC" }, { "name":"菜单", "sub_button":[ { "type":"view", "name":"搜索", "url":"http://www.soso.com/" }, { "type":"miniprogram", "name":"wxa", "url":"http://mp.weixin.qq.com" }, { "type":"click", "name":"赞一下我们", "key":"V1001_GOOD" }] }] }
如此取关测试公众号,然后重新关注就可以看到菜单的变化了。
(3)自己写代码
首先获取access_token,创建WeixinService接口及其实现类、MenuService及其实现类,如图
WerixinServiceImpl实现类代码:
@Service
public class WeixinServiceImpl implements WeixinService {
@Autowired
private RestTemplate restTemplate;
@Override
public AccessTokenVO getAccessToken(String appId, String appSecret) {
AccessTokenVO accessTokenVO = restTemplate.getForObject(Constants.GET_ACCESS_TOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret), AccessTokenVO.class);
return accessTokenVO;
}
}
AccessTokenVO代码
@Data//lombok注解
public class AccessTokenVO {
@ApiModelProperty(value = "获取到的凭证")
private String access_token;
@ApiModelProperty(value = "凭证有效时间,单位:秒(微信目前暂7200秒,即2小时,过期后需再次获取)")
private int expires_in;
}
WeixinResponseResult代码
@Data
public class WeixinResponseResult {
@ApiModelProperty(value = "响应码")
private int errcode;
@ApiModelProperty(value = "响应消息")
private String errmsg;
}
Constants代码
public class Constants { /** * TODO 填写自己的 `appID` 和 `appsecret` */ public static final String APP_ID = "xxxx"; public static final String APP_SECRET = "xxxx"; /** * 通过 `GET请求方式` 获取 `access_token` */ public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * TODO 只做临时方便测试使用 */ public static final String ACCESS_TOKEN = "55_Nm9XUj_ZM-yHUt10mHEZ4BRMuXt-Dlm33pOWcycHy_EfAPlTB7Wd6-j01Hw0VwrqNARbm1jQzro4J1FGhpney0uu6H-7d3ajFM6Vd-85oJ7R6MgY29HlsRQ4cDB63yH1dTqbVrTBulzKnHhxGVAbAAANCH"; /** * 查询菜单接口 - GET请求 */ public static final String GET_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN"; /** * 删除菜单接口 - GET请求 (注意,在个性化菜单时,调用此接口会删除默认菜单及全部个性化菜单) */ public static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN"; /** * 创建菜单接口 - POST请求 */ public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN"; /** * 用户认证 */ public static final String AUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"; /** * 用户认证重定向url */ public static final String AUTH_REDIRECT_URI = "http://iwat.free.idcfengye.com/api/weixin/basic/getOpenId"; /** * 获取用户openid和token */ public static final String AUTH_GET_ACCESS_TOKEN_AND_OPENID = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; /** * 根据token和openid获取用户信息 */ public static final String AUTH_GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN"; /** * 刷新token */ public static final String AUTH_REFRESH_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN"; /** * 检查token是否有效 */ public static final String AUTH_CHECK_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID"; /** * */ public static final String CONTENT_TYPE = ""; }
下面开始测试,代码如下
@Slf4j @RunWith(SpringRunner.class) @SpringBootTest(classes = HelloWechatDepApplication.class) class HelloWechatDepApplicationTests { @Autowired private RestTemplate restTemplate; @Autowired private WeixinService weixinService; @Test // 获取 `access_token` public void getAccessToken() throws Exception { //AccessTokenVO accessTokenVO = weixinService.getAccessToken(Constants.APP_ID, Constants.APP_SECRET); AccessTokenVO accessTokenVO = weixinService.getAccessToken(Constants.APP_ID, Constants.APP_SECRET); log.info("======================================== \n" + accessTokenVO.getAccess_token()); } @Test // 获取 创建菜单 public void createMenu() throws Exception { String menu = "{\n" + " \"button\":[\n" + " {\t\n" + " \"type\":\"click\",\n" + " \"name\":\"今日歌曲\",\n" + " \"key\":\"V1001_TODAY_MUSIC\"\n" + " },\n" + " {\n" + " \"name\":\"菜单\",\n" + " \"sub_button\":[\n" + " {\t\n" + " \"type\":\"view\",\n" + " \"name\":\"搜索\",\n" + " \"url\":\"http://www.soso.com/\"\n" + " },\n" + " {\n" + " \"type\":\"miniprogram\",\n" + " \"name\":\"wxa\",\n" + " \"url\":\"http://mp.weixin.qq.com\"\n" + " },\n" + " {\n" + " \"type\":\"click\",\n" + " \"name\":\"赞一下我们\",\n" + " \"key\":\"V1001_GOOD\"\n" + " }]\n" + " }]\n" + " }"; String jsonMenu = JSONUtil.toJsonStr(menu); WeixinResponseResult result = restTemplate.postForObject(Constants.CREATE_MENU_URL.replace("ACCESS_TOKEN", "上一步中获取的token"), jsonMenu, WeixinResponseResult.class); System.out.println(result); } }
微信模板消息文档:微信公众平台|模板消息 (qq.com)
所谓模版消息就是消息的一种,其中包含预留字段我们可以动态设置内容,主要用于业务通知,例如:我们微信中收到的这样的消息
(1)在进行模板消息测试之前我们首先要定义一个模板,在测试号网页中的消息模板中添加一个消息模板
模板说明:
{{first.DATA}}
申请人:{{keyword1.DATA}}
申请进度:{{keyword2.DATA}}
申请时间:{{keyword3.DATA}}
提交人:{{keyword4.DATA}}
{{remark.DATA}}
{{xxx.DATA}}中的内容就是预留字段,在接口中可以指定值,且必须以 {{first.DATA}} 开头, {{remark.DATA}}结尾,中间也必须是xxx.DATA
(2)测试
首先例如创建菜单时的获取token方法获取access_token
然后在postman进行测试,如下图
URL:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=xxx
请求体内容:
{ "touser": "oC0So6FyAWhsDSzm80m2xrMzw98E", //用户的openID "template_id": "sTLSPG7UgzYfhtWnGcFo5rE9QLZSuRU9FSN-xFYnKoM", //模板消息的模板id "url": "https://www.bilibili.com/", //点击消息跳抓的url "data": { "first": { "value": "您有一条新消息", //渲染到{{first.DATA}} "color": "#173177" }, "keyword1": { "value": "林一", //{{keyword1.DATA}} "color": "#1731FF" }, "keyword2": { "value": "待审批", //{{keyword2.DATA}} "color": "#1731FF" }, "keyword3": { "value": "2038-13-01 12:12:12", //{{keyword3.DATA}} "color": "#1731FF" }, "keyword4": { "value": "秦安", //{{keyword4.DATA}} "color": "#1731FF" }, "remark": { "value": "希望您尽快审批", //{{remark.DATA}} "color": "#173177" } } }
小结:看完创建菜单和消息模板,有的小伙伴可能有些困惑,创建菜单和消息模板和开始说的微信服务器认证没有任何关系,是的仅就这两点而言确实无关,但是如果你要实现用户在公众号发送一条消息,动态回复一条消息,这就需要了,所以忍不认证微信服服,主要是根据需求,这里只是演示使用。但是下面就会用到了。
网页授权文档:微信开放文档 |公众号网页授权,结合微信文档看
公众号网页授权就是在公众号内通过用户点击一个授权链接,用户同意后从而可以获取用户的微信的信息,例如微信的信息就可以完成一些特定的业务。比如在微信公众号菜单中进入某个网页,在网页里显示微信用户信息等等。
(1)首先我们需要一个填写一个微信回调域名(在测试号可以填写IP+端口),从而是的认证后微信可以重定向我们的填写的回调地址
在测试号网页中修改:
填写:
用户授权就是点击如下的微信链接,链接含义说明如下
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
解析:
1、scope
以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
2、appid
公众号的appid
3、redirect_uri
认证后微信回访问的地址,这里我们可以写接口地址,或者写一个页面地址都可以,因为用户认证之后微信就会访问它。
例如填写http://119.345.9.10:5500/sys/getopenid,认证成功后为微信就会调用http://119.345.9.10:5500/sys/getopenid?code=xxxxxx;
填写http://119.345.9.10:5500/show.html,认证成功后为微信就重定向到页面http://119.345.9.10:5500/show.html?code=xxxxxx,携带者code参数
注意:这里的回调地址必须是外网能够访问的,因为微信服务器要访问这个地址,它必须能够访问到才行。所以这里就可以使用第一步微信授权时候做的内网穿透了,测试号页面的回调地址就可以写下面的域名。
(2)正式开始我们的认证过程
首先微信测试号页面填写回调地址域名
(3)在WeixinService接口新增方法
WeixinServiceImpl代码
@Override public void getOpenId(HttpServletRequest request, HttpServletResponse response) { String code = request.getParameter("code"); String state = request.getParameter("state"); log.debug("======================================= \n code值:" + code); String responseContent = restTemplate.getForObject(Constants.AUTH_GET_ACCESS_TOKEN_AND_OPENID .replace("APPID", Constants.APP_ID) .replace("SECRET", Constants.APP_SECRET) .replace("CODE", code), String.class); JSONObject result = JSONUtil.parseObj(responseContent); String accessToken = result.getStr("access_token"); String openid = result.getStr("openid"); String refreshToken = result.getStr("refresh_token"); log.debug("======================================= \n access_token值:" + accessToken + "\n openid值:" + openid); //这里要修改为你自己的域名 String redirectUrl = "http://iwat.free.idcfengye.com/api/weixin/basic/getUserInfo?openid=" + openid + "&access_token=" + accessToken; try { // 授权之后重定向到指定URL(这里是跳转到获取用户基本信息接口) response.sendRedirect(redirectUrl); } catch (IOException e) { e.printStackTrace(); } } @Override public WeixinUserInfoVO getUserInfo(String openId, String accessToken) { WeixinUserInfoVO weixinUserInfoVO = null; String responseContent = restTemplate.getForObject(Constants.AUTH_GET_USER_INFO .replace("ACCESS_TOKEN", accessToken) .replace("OPENID", openId), String.class); weixinUserInfoVO = JSONUtil.toBean(responseContent, WeixinUserInfoVO.class); return weixinUserInfoVO; }
新增WeixinController
WeixinController代码如下
@Slf4j @RestController @RequestMapping("/api/weixin/basic") @Api(tags = "微信授权 - 接口") public class WeixinController extends BaseController { @Autowired private WeixinService weixinService; @GetMapping(value = "/getOpenId"/*, produces = Constants.CONTENT_TYPE*/) @ApiOperation(value = "回调地址获取code换取access_token和openid", httpMethod = "GET", response = ApiResult.class, notes = "回调地址获取code换取access_token和openid") public ApiResult getOpenId(HttpServletRequest request, HttpServletResponse response) { weixinService.getOpenId(request, response); return ApiResult.ok("回调地址获取code换取access_token和openid成功!"); } @GetMapping(value = "/getUserInfo"/*, produces = Constants.CONTENT_TYPE*/) @ApiOperation(value = "获取用户基础信息", httpMethod = "GET", response = ApiResult.class, notes = "获取用户基础信息") public ApiResult getUserInfo(@RequestParam("openid") String openid, @RequestParam(value = "access_token", required = false) String accessToken) { WeixinUserInfoVO result = weixinService.getUserInfo(openid, accessToken); return ApiResult.ok("获取用户基础信息成功!", result); } }
(4)修改用户菜单
在菜单测试那里,修改菜单内容如下。
{ "button":[ { "type":"click", "name":"今日歌曲", "key":"V1001_TODAY_MUSIC" }, { "name":"菜单", "sub_button":[ { "type":"view", "name":"测试网页授权", "url":"https://open.weixin.qq.com/connect/oauth2/authorize?appid=你的APPID&redirect_uri=iwat.free.idcfengye.com/api/weixin/basic/getOpenId&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect " }, { "type":"miniprogram", "name":"wxa", "url":"http://mp.weixin.qq.com" }, { "type":"click", "name":"赞一下我们", "key":"V1001_GOOD" }] }] }
取关公众号,重新关注,菜单就会刷新,测试即可。
如有不足欢迎指正!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。