记一次微信公众号开发记录
微信公众号开发还是相对简单的,来来回回写过几次了,一直没有详细的记录下来,导致每次写还是要查文档,现将这次开发经历记录下来,以备不时之需。
- pom.xml文件中引入下面的三方sdk
<!--微信公众号三方sdk-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
微信开发 Java SDK(开发工具包),官网还有支持包括微信支付、开放平台、小程序、企业微信/企业号的sdk,简直好用!!!
- application.yml配置
# 公众号配置(必填)
wx:
mp:
appId: APPID #微信公众号的appid
secret: SECRET #微信公众号的app corpSecret
token: TOKEN #微信公众号的token
aesKey: AESKEY #微信公众号的EncodingAESKey
重定向进行微信网页授权获取用户信息并重定向回去
- 思路
1. 提供一个前端重定向过来的入口,URL上携带一个redirect_url参数(代表从微信获取用户信息后要重定向回去的页面),并在此处跳转到微信进行网页授权。
2. 授权成功后获取code。
3. 通过code调微信接口获取openid和access_token。
4. 获取用户信息。
5. 最后重定向回最初的redirect_url,并拼上想要的参数。
- 实现
1. 首先提供一个前段重定向过来的入口,URL上携带一个redirect_url参数(代表从微信获取用户信息后要重定向回去的页面),并在此处跳转到微信进行网页授权。
- 注意
redirect_url需要经过
URLEncoder
,拿到之后再进行URLDecoder
,否则redirect_url中#
之后的部分会丢掉。最好进行两次
URLEncoder
,两次URLDecoder
,因为有的浏览器会自动解码。
//微信授权后返回的地址
private String getCodeUrl = "项目域名" + "redirect/code?redirect_url=";
//默认重定向地址defaultUrl
private String defaultUrl = "[DEFAULT_URL]";
//提供的获取用户信息的重定向入口地址
@GetMapping("/redirect")
public String redirect(
@RequestParam(name = "redirect_url", defaultValue = "", required = false) String redirectUrl
) throws UnsupportedEncodingException {
//默认重定向地址defaultUrl
if (StringUtils.isBlank(redirectUrl)) {
redirectUrl = defaultUrl;
} else {
redirectUrl = URLDecoder.decode(redirectUrl, "utf-8");
LOGGER.info("一次解码:{}",redirectUrl);
redirectUrl = URLDecoder.decode(redirectUrl, "utf-8");
LOGGER.info("二次解码:{}",redirectUrl);
}
LOGGER.info("redirectUrl:{}",redirectUrl);
//一次编码
redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
LOGGER.info("一次编码url:{}",redirectUrl);
//二次编码
redirectUrl = URLEncoder.encode(getCodeUrl + redirectUrl, "utf-8");
LOGGER.info("二次编码url:{}",redirectUrl);
//最终得到微信授权地址
String url = wxMpService.oauth2buildAuthorizationUrl(redirectUrl,"snsapi_userinfo","123");
LOGGER.info("最终得到微信授权地址:{}",url);
//跳转授权
return "redirect:" + url;
}
2. 授权成功后获取code。
3. 通过code调微信接口获取openid和access_token。
4. 获取用户信息。
5. 最后重定向回最初的redirect_url,并拼上想要的参数。
-
下面完成2、3、4、5步
需要定义一个连接,就是上一步中的
getCodeUrl
,由微信授权成功后重定向到这个链接,并携带code参数。由于上一步我们将redirect_url进行了两次编码,所以redirect_url也会传递进来。
//错误页面errorPage
private String errorPage = "[ERROR_PAGE]";
//这里的地址由微信重定向跳转,携带获取的code参数。
@GetMapping("/redirect/code")
public void getCode(
@RequestParam(name = "redirect_url", defaultValue = "", required = false) String redirectUrl,
@RequestParam(name = "code", defaultValue = "", required = false) String code,
HttpServletRequest request,HttpServletResponse response
) throws IOException {
LOGGER.info("redirect_url: {}", redirectUrl);
LOGGER.info("code: {}", code);
if (StringUtils.isBlank(code)) {
LOGGER.error("获取code失败");
LOGGER.info("重定向到错误页,errorPage:{}",errorPage);
response.sendRedirect(errorPage + "?error=code-is-null");
}
//解码重定向地址
redirectUrl = URLDecoder.decode(redirectUrl, "utf-8");
LOGGER.info("解码重定向地址url:{}",redirectUrl);
//根据code获取微信相关信息
try {
//根据code获取openid和access_token
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
//获取微信用户信息
WxMpUser wxMpUser = wxMpService.getUserService().userInfo(wxMpOAuth2AccessToken.getOpenId());
LOGGER.info("userInfo:{}",wxMpUser.toString());
} catch (WxErrorException e) {
e.printStackTrace();
LOGGER.info("重定向到错误页,errorPage:{}",errorPage);
response.sendRedirect(errorPage + "?error=" + e.getMessage());
}
//这里直接将微信用户信息编码后重定向给最开始的redirect_url
response.sendRedirect(redirectUrl + "?wechat_user=" + URLEncoder.encode(wxMpUser.toString(), "utf-8"));
}
微信模版消息推送
微信模板消息推送也比较简单,核心代码只有下面几行,最主要的获取用户openid在上面已经讲过,在这里就不再赘述。
public String push() throws Exception {
//推送消息
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser("[OPENID]") //要推送的用户openid
.templateId("[TEMPLATEID]") //模版id
.url("[URL]") //点击模版消息要访问的网址
.build();
templateMessage.addData(new WxMpTemplateData("first","[标题]","[COLOR]"));
templateMessage.addData(new WxMpTemplateData("keyword1","[消息主体]","[COLOR]"));
...//keywordn是模板规定的
templateMessage.addData(new WxMpTemplateData("remark","[备注]","[COLOR]"));
//开始推送
try {
wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
return "true";
} catch (WxErrorException e) {
System.out.println("推送失败:" + e.getMessage());
e.printStackTrace();
WxError wxError = e.getError();
if ("43004".equals(wxError.getErrorCode())){
throw new Exception("该用户未关注公众号");
}
throw new Exception(wxError.getErrorMsg());
}
}