目的
本次实现的目的是:在微信公众号项目中,可能在每次访问页面的时候需要带上openid或者授权,查数据库太耗性能、多次多个地方去调授权接口也不是最佳的方案,如果能利用拦截器拦截到每次请求访问后台,这个时候在拦截器里判断是否已经有这个粉丝的openid,如果获取到了openid,就不用去走授权获取用户信息接口了,那么从哪里取这个openid呢,可以从Redis或其他缓存库里取,我使用了的拦截器处理:从Session里去取openid,取openid的前提是在第一次授权获取用户信息后,你需要将openId存到session里去,然后每次请求拦截器会拦截相关Api请求,从session中获取openid,然后判断openid,以此来做业务判断,如果获取不到就去走授权接口;
一、实现
1.创建一个拦截器,拦截器配置如下,对拦截器不熟悉的请看:如何自定义一个拦截器
在spring-mvc.xml文件中新增一个拦截器 (注:如果是SpringBoot项目,请按照SpringBoot创建拦截器方式创建拦截器)
<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。--><mvc:interceptors><!-- 微信授权拦截器 --><mvc:interceptor><mvc:mapping path="/mobile/**" /><bean class="com.thinkgem.jeesite.modules.sys.interceptor.WXOAuthInterceptor" /></mvc:interceptor></mvc:interceptors>
2.新建一个拦截器类WXOAuthInterceptor
WXOAuthInterceptor.java
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import com.mon.service.BaseService;import com.mon.utils.StringUtils;import com.thinkgem.jeesite.modules.wechat.service.WXOAuthService;/*** 微信* * <pre>* * @author cao_wencao * @date 8月13日* </pre>*/@Slf4jpublic class WXOAuthInterceptor extends BaseService implements HandlerInterceptor {@Autowiredprivate WXOAuthService wXOAuthService;@Override@Transactional(readOnly = false)public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {// 获取 seesion openidlog.warn("==============执行顺序: 1、preHandle================");String openid = (String) request.getSession().getAttribute("openid");if (StringUtils.isNotBlank(openid)){return true;}String code = request.getParameter("code"); // 获取参数中 的 code 参数if (StringUtils.isNotBlank(code)) {wXOAuthService.userInfo(request, response);} else {wXOAuthService.oauth(request, response);}return true;}@Override@Transactional(readOnly = false)public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {log.warn("==============执行顺序: 2、postHandle================");//request.getSession().setAttribute("openid", "oJIGa0RLwXB8r5vxYphyKCOQGxz1"); // 设置 Session Openid//// 获取 seesion openid}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {log.warn("==============执行顺序: 3、afterCompletion================");}}
3.授权接口服务类WXOauthService
注:WXOauthService中userInfo方法为请求授权接口,在请求授权获取用户信息后需要将openid存进session里去,这样在拦截器中才可以取到粉丝的openid
import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import me.mon.api.WxConsts;import me.mon.exception.WxErrorException;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;import me.chanjar.weixin.mp.bean.result.WxMpUser;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import com.mon.utils.StringUtils;import com.thinkgem.jeesite.modules.app.entity.user.Follow;import com.thinkgem.jeesite.modules.app.service.user.FollowService;import com.thinkgem.jeesite.modules.app.service.user.MemberService;import com.thinkgem.jeesite.modules.wechat.receiveVo.FansVo;/*** 网页授权 服务* @author caowencao**/@Service@Transactional(readOnly = true)public class WXOAuthService {private static final Logger logger = LoggerFactory.getLogger(WXOAuthService.class);@Autowiredprivate WxMpService wxMpService;@Autowiredprivate FollowService followService;@Autowiredprivate MemberService memberService;/*** 网页授权* @param request* @param response* @throws IOException */public void oauth(HttpServletRequest request, HttpServletResponse response) throws Exception{String backUrl = request.getRequestURL().toString(); //取得当前 URLString redirectUri = wxMpService.oauth2buildAuthorizationUrl(backUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO,"1");logger.info("redirectUri地址={}", redirectUri);// 日志response.sendRedirect(redirectUri);}/*** 获取用户信息* @param request* @param response* @throws IOException */@Transactional(readOnly = false)public void userInfo(HttpServletRequest request, HttpServletResponse response) throws Exception{String code = request.getParameter("code");if(StringUtils.isBlank(code))oauth(request, response); //继续授权// 通过code换取access tokenWxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();String openId = null;try {wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);openId = wxMpOAuth2AccessToken.getOpenId();logger.info("openId={}", openId);String lang = "zh_CN";WxMpUser wxMpUser = this.wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, lang);// TODO 操作保存用户信息到数据库// 保存通过授权拿到的用户信息followService.saveOauthFollowInfo(wxMpUser);// Follow follow = followService.findFollowByOpenId(openId);// if (null == follow && null != wxMpUser) {//// 保存通过授权拿到的用户信息//followService.saveOauthFollowInfo(wxMpUser);// }logger.info("网页授权获取用户信息 :" + wxMpUser.toString());FansVo fans = new FansVo();// 获取粉丝账号String account = memberService.getAccountByOpenid(openId);if (!StringUtils.isBlank(account)) {fans.setAccount(account);fans.setOpenid(openId);} request.getSession().setAttribute("fans", fans); // session中设置粉丝账号和openidrequest.getSession().setAttribute("openid", openId); //设置 Session Openid}catch (WxErrorException e) {logger.error("【微信网页授权】{}", e.getMessage());oauth(request, response);throw new RuntimeException("网页授权失败!");}}}
好了,到这里使用拦截器获取微信openID、授权获取用户信息就实现了,像这样封装复用性比较高;