微信公众号开发之扫码关注并登陆实战
<div><p>好久又没有更新文章了,最近又在忙项目,开发中遇到了一个需求,就是用户扫码二维码之后没有关注公众号,要先关注之后才能登陆,如果已经关注了就直接跳登陆成功,其实这个功能应用场景还是蛮多的,包括腾讯自己的应用也使用了这样的功能。下面开始分享给需要的伙伴们,当然,这我自己的摸索实现的,可能还有更好的方案,如果小伙伴们有更好的方法,欢迎分享交流,话不多说开干!</p>
<p>一.思路分析:<br>
1.使用公众号接口生成二维码。<br>
2.系统接收微信推送过来的事件(关注/扫码)。<br>
3.用户点击关注或者扫码二维码后台都会接收到推送通知,然后根据通知实现自己的业务就可以了。</p>
<p>二.开发环境:<br>
1.idea<br>
2.redis<br>
3.springboot2.x</p>
<p>三.基础环境搭建:<br>
1.新建一个springboot项目<br>
2.添加一个控制器,并运行,保证项目正常。</p>
<p>四.业务开发:</p>
<p><br> 1.让系统和微信系统对接上,能够接收微信推送事件,在控制器上面新增两个方法</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">*
* 微信服务器触发get请求用于检测签名
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@GetMapping(</span>"/handleWxCheckSignature"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String handleWxCheckSignature(HttpServletRequest request){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">todo 严格来说这里需要做签名验证,我这里为了方便就不做了</span>
String echostr = request.getParameter("echostr"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> echostr;
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 接收微信推送事件
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> request
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@PostMapping(</span>"/handleWxCheckSignature"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String handleWxEvent(HttpServletRequest request){
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
InputStream inputStream </span>=<span style="color: rgba(0, 0, 0, 1)"> request.getInputStream();
Map</span><String, Object> map =<span style="color: rgba(0, 0, 0, 1)"> XmlUtil.parseXML(inputStream);
String userOpenId </span>= (String) map.get("FromUserName"<span style="color: rgba(0, 0, 0, 1)">);
String event </span>= (String) map.get("Event"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span>("subscribe"<span style="color: rgba(0, 0, 0, 1)">.equals(event)){
logger.info(</span>"用户关注:{}"<span style="color: rgba(0, 0, 0, 1)">,userOpenId);
}</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>("SCAN"<span style="color: rgba(0, 0, 0, 1)">.equals(event)){
logger.info(</span>"用户扫码:{}"<span style="color: rgba(0, 0, 0, 1)">,userOpenId);
}
logger.info(</span>"接收参数:{}"<span style="color: rgba(0, 0, 0, 1)">,map);
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "success"<span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p> </p>
</div>
<p>2.在公众号后台设置URL和token,为了方面演示,我使用了公众号测试账号,同时使用了natapp做了外网映射,保存验证成功即可:</p>
<p> </p>
<p><img src="https://img2022.cnblogs.com/blog/1838865/202203/1838865-20220331170941306-726301205.png"></p>
<p> </p>
<p> </p>
<p> 3.用手机扫一下自己的公众号测试专用二维码:</p>
<p> </p>
<p><img src="https://img2022.cnblogs.com/blog/1838865/202203/1838865-20220331170956271-254999659.png"></p>
<p> </p>
<p> </p>
<p> 点击关注看看控制台是否有接收到通知,接收到即可继续往下:</p>
<p><img src="https://img2022.cnblogs.com/blog/1838865/202203/1838865-20220331171012640-1216328823.png"></p>
<p> </p>
<p> </p>
<p> </p>
<p> 2.注入RestTemplate用于http请求 :</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 注入restTemplate用于http请求
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@Configuration
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> RestTemplateConfig {
@Resource
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> RestTemplateBuilder templateBuilder;
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RestTemplate restTemplate(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> templateBuilder.build();
}
}</span></pre>
</div>
<p> </p>
<p>3.新增一个微信服务接口,用于调用微信公众号接口</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> WxService {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取token</span>
<span style="color: rgba(0, 0, 0, 1)"> String getAccessToken();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取生成二维码参数</span>
Map<String,Object><span style="color: rgba(0, 0, 0, 1)"> getQrCode();
}</span></pre>
</div>
<p> </p>
<p>4.实现接口调用, 不清楚请看微信公众号开发文档。</p>
<p>yml中配置公众号参数</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">spring:
# 模版配置
thymeleaf:
cache: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
#redis 配置
redis:
host: </span>127.0.0.1<span style="color: rgba(0, 0, 0, 1)">
database: </span>1<span style="color: rgba(0, 0, 0, 1)">
password: </span>123456<span style="color: rgba(0, 0, 0, 1)">
#公众号参数配置
wx:
gz:
appid:你的appid
secret: 你的appsecret</span></pre>
</div>
<p> </p>
<p>接口服务实现:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">@Service
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> WxServiceImpl <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> WxService {
Logger logger </span>= LoggerFactory.getLogger(WxServiceImpl.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
@Value(</span>"${wx.gz.appid:''}"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String appid;
@Value(</span>"${wx.gz.secret:''}"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String secret;
@Resource
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> RestTemplate restTemplate;
@Resource
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> RedisCacheManager redisCacheManager;
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getAccessToken() {
String key </span>= "wx_access_token"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从redis缓存中获取token</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(redisCacheManager.hasKey(key)){
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (String) redisCacheManager.get(key);
}
String url </span>= String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"<span style="color: rgba(0, 0, 0, 1)">,appid,secret);
ResponseEntity</span><String> result = restTemplate.getForEntity(url, String.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(result.getStatusCode()==<span style="color: rgba(0, 0, 0, 1)"> HttpStatus.OK){
JSONObject jsonObject </span>=<span style="color: rgba(0, 0, 0, 1)"> JSON.parseObject(result.getBody());
String access_token </span>= jsonObject.getString("access_token"<span style="color: rgba(0, 0, 0, 1)">);
Long expires_in </span>= jsonObject.getLong("expires_in"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">缓存toekn到redis</span>
<span style="color: rgba(0, 0, 0, 1)"> redisCacheManager.set(key,access_token,expires_in);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> access_token;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Map<String, Object><span style="color: rgba(0, 0, 0, 1)"> getQrCode() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取临时二维码</span>
String url = String.format("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s"<span style="color: rgba(0, 0, 0, 1)">,getAccessToken());
ResponseEntity</span><String> result = restTemplate.postForEntity(url, "{\"expire_seconds\": 604800, \"action_name\": \"QR_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"test\"}}}", String.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
logger.info(</span>"二维码:{}"<span style="color: rgba(0, 0, 0, 1)">,result.getBody());
JSONObject jsonObject </span>=<span style="color: rgba(0, 0, 0, 1)"> JSON.parseObject(result.getBody());
Map</span><String,Object> map=<span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><span style="color: rgba(0, 0, 0, 1)">();
map.put(</span>"ticket",jsonObject.getString("ticket"<span style="color: rgba(0, 0, 0, 1)">));
map.put(</span>"url",jsonObject.getString("url"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> map;
}
} </span></pre>
</div>
<p> </p>
<p>5.ok,接下来就是在控制器中新增一个首页和一个登陆和登陆成功方法</p>
<div class="cnblogs_code">
<pre> @GetMapping(""<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String index(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "index"<span style="color: rgba(0, 0, 0, 1)">;
}
@GetMapping(</span>"/login"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String login(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "login"<span style="color: rgba(0, 0, 0, 1)">;
}
@GetMapping(</span>"/success"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String loginSuccess(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "登陆成功"<span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p> </p>
<p>简单html页面</p>
<p>index.html</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><!</span><span style="color: rgba(255, 0, 255, 1)">DOCTYPE html</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">html </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="en"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">meta </span><span style="color: rgba(255, 0, 0, 1)">charset</span><span style="color: rgba(0, 0, 255, 1)">="UTF-8"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">title</span><span style="color: rgba(0, 0, 255, 1)">></span>微信公众号扫码关注登陆实现<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">title</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">body</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">a </span><span style="color: rgba(255, 0, 0, 1)">href</span><span style="color: rgba(0, 0, 255, 1)">="/login"</span><span style="color: rgba(0, 0, 255, 1)">></span>扫码登陆<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">a</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">body</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">html</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p> </p>
<p>login.html</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><!</span><span style="color: rgba(255, 0, 255, 1)">DOCTYPE html</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">html </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="en"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">meta </span><span style="color: rgba(255, 0, 0, 1)">charset</span><span style="color: rgba(0, 0, 255, 1)">="UTF-8"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">title</span><span style="color: rgba(0, 0, 255, 1)">></span>登陆<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">title</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">body</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">div </span><span style="color: rgba(255, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">="width: 200px;margin: 50px auto"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">div </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="qrcode"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">='text/javascript' </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">='http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js'</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(255, 0, 0, 1)"> src</span><span style="color: rgba(0, 0, 255, 1)">="http://cdn.staticfile.org/jquery.qrcode/1.0/jquery.qrcode.min.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
$(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> () {
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">获取二维码参数</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> $.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/getQrCode</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (res) {
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">生成二维码</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> $(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#qrcode</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">).qrcode(res.url);
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">轮训获取用户扫码登陆状态</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> task </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> setInterval(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> () {
$.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/checkLogin</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,{ticket:res.ticket},</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (ok) {
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">扫码成功登陆成功</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(ok){
clearInterval(task)
location.href</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/success</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
}
})
},</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">2000</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">)
})
})
</span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">body</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">html</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p> </p>
<p>用到的maven依赖</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>dom4j<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>dom4j<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>1.6.1<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>com.alibaba<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>fastjson<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>1.2.68<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p> </p>
<p>自己用dom4j简单解析xml</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> XmlUtil {
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 简单解析xml
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> in
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Map<String,Object><span style="color: rgba(0, 0, 0, 1)"> parseXML(InputStream in){
Map</span><String,Object> map=<span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
SAXReader saxReader </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SAXReader();
Document document </span>=<span style="color: rgba(0, 0, 0, 1)"> saxReader.read(in);
Element root </span>=<span style="color: rgba(0, 0, 0, 1)"> document.getRootElement();
Iterator iterator </span>=<span style="color: rgba(0, 0, 0, 1)"> root.elementIterator();
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (iterator.hasNext()){
Element element </span>=<span style="color: rgba(0, 0, 0, 1)"> (Element) iterator.next();
map.put(element.getName(),element.getStringValue());
}
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (DocumentException e) {
e.printStackTrace();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> map;
}
}</span></pre>
</div>
<p> </p>
<p>自己简单包装的redis缓存工具</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">@Component
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> RedisCacheManager {
@Resource
</span><span style="color: rgba(0, 0, 255, 1)">private</span> RedisTemplate<String,Object><span style="color: rgba(0, 0, 0, 1)"> redisTemplate;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> set(String key,Object value,<span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> expire){
redisTemplate.opsForValue().set(key,value,expire, TimeUnit.SECONDS);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Object get(String key){
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> redisTemplate.opsForValue().get(key);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Boolean delete(String key){
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> redisTemplate.delete(key);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> hasKey(String key) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> redisTemplate.hasKey(key);
}
}</span></pre>
</div>
<p> </p>
<p>改造controller</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">@Controller
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> HomeController {
Logger logger </span>= LoggerFactory.getLogger(HomeController.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
@Resource
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> WxService wxService;
@Resource
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> RedisCacheManager redisCacheManager;
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 首页
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@GetMapping(</span>"/"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String index(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "index"<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 登陆页面
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@GetMapping(</span>"/login"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String login(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "login"<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 用于检测扫码和关注状态
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@PostMapping(</span>"/checkLogin"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Object checkLogin(String ticket){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果redis中有ticket凭证则说明用户已扫码说明登陆成功</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(redisCacheManager.hasKey(ticket)){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">扫码通过则删除</span>
<span style="color: rgba(0, 0, 0, 1)"> redisCacheManager.delete(ticket);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 获取二维码参数
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@GetMapping(</span>"/getQrCode"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Object getQrCode(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> wxService.getQrCode();
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 登陆成功跳转
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@GetMapping(</span>"/success"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String loginSuccess(){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "登陆成功"<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">*
* 微信服务器触发get请求用于检测签名
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@GetMapping(</span>"/handleWxCheckSignature"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String handleWxCheckSignature(HttpServletRequest request){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">todo 严格来说这里需要做签名验证,我这里为了方便就不做了</span>
String echostr = request.getParameter("echostr"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> echostr;
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 接收微信推送事件
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> request
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@PostMapping(</span>"/handleWxCheckSignature"<span style="color: rgba(0, 0, 0, 1)">)
@ResponseBody
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String handleWxEvent(HttpServletRequest request){
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
InputStream inputStream </span>=<span style="color: rgba(0, 0, 0, 1)"> request.getInputStream();
Map</span><String, Object> map =<span style="color: rgba(0, 0, 0, 1)"> XmlUtil.parseXML(inputStream);
String userOpenId </span>= (String) map.get("FromUserName"<span style="color: rgba(0, 0, 0, 1)">);
String event </span>= (String) map.get("Event"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span>("subscribe"<span style="color: rgba(0, 0, 0, 1)">.equals(event)){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO:获取openid判断用户是否存在,不存在则获取新增用户,自己的业务
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自己生成的二维码不管是关注还是扫码都能取到ticket凭证,这里我使用Ticket作为每次二维码的唯一标识</span>
String ticket = (String) map.get("Ticket"<span style="color: rgba(0, 0, 0, 1)">);
redisCacheManager.set(ticket,</span>"",10*60<span style="color: rgba(0, 0, 0, 1)">);
logger.info(</span>"用户关注:{}"<span style="color: rgba(0, 0, 0, 1)">,userOpenId);
}</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>("SCAN"<span style="color: rgba(0, 0, 0, 1)">.equals(event)){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自己生成的二维码不管是关注还是扫码都能取到ticket凭证</span>
String ticket = (String) map.get("Ticket"<span style="color: rgba(0, 0, 0, 1)">);
redisCacheManager.set(ticket,</span>"",10*60<span style="color: rgba(0, 0, 0, 1)">);
logger.info(</span>"用户扫码:{}"<span style="color: rgba(0, 0, 0, 1)">,userOpenId);
}
logger.info(</span>"接收参数:{}"<span style="color: rgba(0, 0, 0, 1)">,map);
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "success"<span style="color: rgba(0, 0, 0, 1)">;
}
}</span></pre>
</div>
<p> </p>
<div>
<div>
<p>说明: 通过微信获取二维码参数时里面有ticket和用户扫码之后都会携带这个参数,所以我就将就使用这个凭证作为用户是否扫码的判断了。即,当用户扫我们生成的二维码,收到关注或者扫码事件时,说明用户已扫码或关注,此时将这个二维码的ticket存到redis中, 与前端传过来的ticket对比,如果一致则说明扫码成功,跳转到登陆成功页面!</p>
<p>6.测试效果:<br>
扫码</p>
</div>
<img src="https://img2022.cnblogs.com/blog/1838865/202203/1838865-20220331171745941-933561404.jpg"><br><br>
<p> </p>
<p> 扫码登陆成功</p>
<p><img src="https://img2022.cnblogs.com/blog/1838865/202203/1838865-20220331171538805-197921252.png"></p>
<p> </p>
<p> </p>
<div>
<div>
<p>因为这个测试不好演示,我就简单的模拟结果了。</p>
<p>总结:公众号扫码登陆就简简单单的完成了,当然这只是一个模拟流程,具体的业务<br>
还需要自己实现。这也是我在做项目中遇到的一个实际需求,这里分享出来,如果有不对的地方欢迎大家指正,如果喜欢我的文章,记得关注不迷路,后续会分享更多干货😊!</p>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/xingmatong/p/16082852.html
頁:
[1]