之前做过几次微信公众号开发, 一直没有记录下开发过程, 为方便以后不用在去各种搜索找资料, 在此记录开发流程...
首先, 开通微信公众号, 电梯直达(公众号申请).
第二步, 绑定开发者权限, 方便使用开发者工具调试
一切准备就绪, 接下来分析微信公众号授权流程, 下图简单介绍授权序列图:
在没有弄清楚该流程之前, 我一直有个疑惑, 到底该何时提示用户授权呢? 也就是说微信服务器与我们的业务服务器在哪里作为切入点.
这里可以有两种方式提示用户授权:
public class LoginInterceptor extends HandlerInterceptorAdapter {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String path = request.getServletPath();
HandlerMethod method = (HandlerMethod) handler;
Method originO = method.getMethod();
Class> clazz = originO.getDeclaringClass();
LoginValidation classAnnotation = clazz.getAnnotation(LoginValidation.class);
LoginValidation methonAnnotation = method.getMethodAnnotation(LoginValidation.class);
boolean needLogin = (null != methonAnnotation || null != classAnnotation);
boolean isGuest = (null == WebUtil.getUser());
if (needLogin && isGuest) {
ResponseBody responseBody = ((HandlerMethod) handler).getMethodAnnotation(ResponseBody.class);
boolean isReqData = (null != responseBody);
if (isReqData)
path = "/"; // 如果是数据请求, 授权后返回首页
redirectAuth(request, response, path);
return false;
}
return true;
}
private void redirectAuth(HttpServletRequest request, HttpServletResponse response, String path) throws Exception {
LOGGER.info("用户未登录, 跳转到授权页面");
boolean normalReq = !isAjaxRequest(request);
String redirectPath = "/wx/auth";
if (normalReq) {
response.sendRedirect(redirectPath);
} else {
Map map = Maps.newHashMap();
map.put("flag", false);
map.put("redirect", redirectPath);
WebUtil.writeJSON(map);
}
WebUtil.setSessionAttr(Constants.SESSION_WECHAT_AUTH_BEFORE_PATH, path);
}
public boolean isAjaxRequest(HttpServletRequest request) {
String header = request.getHeader("X-Requested-With");
boolean isAjax = "XMLHttpRequest".equals(header) ? true : false;
return isAjax;
}
}
@Controller
@RequestMapping("/wx")
public class WeChatController {
private static final String APP_ID = "wx1xxxxxxxxxxxxxxx";
private static final String APP_SECURITY = "aa23461daxxxxxxxxxxxxxxxxxxxxxxxxx";
@Autowired
private UserService userService;
/**
* 构建授权页面
*/
@RequestMapping("auth")
public String auth();
/**
* 微信服务器回调接口
* @param code 用于换区access_Token, 用来获取用户数据
* @param state 自定义数据
*/
@RequestMapping("callback")
public String callback(String code, String state)
}
一切准备接续, 接下来重点关注 WeChatController, 我们先来看看 auth 这个接口的实现
@RequestMapping("auth")
public String auth() {
// 本地开发 WebUtil.getBaseUrl() 总是为 localhost
// String callback = URLEncoder.encode(WebUtil.getBaseUrl() + "wx/callback", "UTF-8");
String callback = StringUtil.encodeUrl("http://df52b8f6.ngrok.io/wx/callback", "UTF-8");
String url = WeChatUtil.createUrl(WeChatUtil.newAuthorizeParam(APP_ID, callback, WeChatUtil.Scope.SNSAPI_USERINFO, null));
return "redirect:" + url;
}
通过 WeChatUtil.createUrl() 通过简单封装, 构建一个微信授权的重定向链接, 该链接中包含以下几部分,
/**
* 微信服务器回调接口
* @param code 用于换区access_Token, 用来获取用户数据
* @param state 自定义数据
*/
@RequestMapping("callback")
public String callback(String code, String state) {
AccessData accessData = WeChatUtil.accessToken(WeChatUtil.newAccessParam(code, APP_ID, APP_SECURITY));
String openId = accessData.getOpenId();
User user = userService.getByOpenId(openId);
if (null == user) {
WeChatUser wxUserInfo = accessData.getUser();
user = userService.loginByWeChat(wxUserInfo);
}
WebUtil.setUser(user);
String path = WebUtil.getSessionAttr(Constants.SESSION_WECHAT_AUTH_BEFORE_PATH);
return "redirect:" + path;
}
WeChatUtil.accessToken() 通过回调参数 code 获取 AccessData 对象, 通过该对象可以获取到 openid 和 WeChatUser 数据.
根据具体业务使用 WeChatUser 对象即可.
三步获取用户数据总结:
第一步, 构建授权重定向地址 WeChatUtil.createUrl(WeChatUtil.newAuthorizeParam(appId, callback, WeChatUtil.Scope, state))
第二步,获取用户授权 AccessData accessData = WeChatUtil.accessToken(WeChatUtil.newAccessParam(code, appId, security));
第三步,获取用户数据 WeChatUser wxUserInfo = accessData.getUser();
WeChatUtil相关代码: https://gitee.com/osby/third/tree/master/src/main/java/org/yong/third/wx