本文共 8221 字,大约阅读时间需要 27 分钟。
1.先定义接口
package com.example.mongodemo.framework.wechat;import com.example.mongodemo.framework.wechat.entity.AccessToken;import com.example.mongodemo.framework.wechat.entity.ImageTicket;import com.example.mongodemo.framework.wechat.entity.LoginUser;import org.checkerframework.checker.signature.qual.FieldDescriptorForPrimitive;/** * @Author lyr * @create 2020/4/19 15:54 */public interface WechatTemplate { /** * 获取token的 url,没什么用 * @return 生成获取 token的 url */ @Deprecated String generateTokenUrl(); /** * 请求微信接口,获取 accessToken * @return 返回微信的 ACCESS_TOKEN */ AccessToken getAccessTokenObject(); /** * 查看用户的登录状态 * @param sceneId 场景id * @return 返回登录状态的包装类 */ LoginUser isUserLogin(String sceneId); /** * 查看用户是否登录,后台确认登录了,返回true,否则返回 false * @param sceneId 用户场景id * @return */ boolean userIsLogin(String sceneId); /** * 设置用户已经登录 * @param sceneId 用户场景id => 表示唯一的用户 */ void setUserIsLogin(String sceneId); /** * 获取扫描二维码的图片门票 * @return 获取扫码二维码的图片门票 */ ImageTicket getImageTicket(); /** * 生成访问二维码的 url * @param ticket 门票对象 * @return */ String generateQrCodeUrl(ImageTicket ticket);}
下面是 AccesToken 的 pojo 等等
package com.example.mongodemo.framework.wechat.entity;import com.fasterxml.jackson.annotation.JsonProperty;import lombok.Data;/** * @Author lyr * @create 2020/4/19 13:50 */@Datapublic class AccessToken { /** * redis前缀 */ public static final String REDIS_KEY = "ac_tk::actk"; @JsonProperty("access_token") private String accessTokenContent; @JsonProperty("expires_in") private Long expiresIn;}
// 生成二维码的门票
package com.example.mongodemo.framework.wechat.entity;import com.fasterxml.jackson.annotation.JsonProperty;import lombok.Data;import lombok.experimental.Accessors;/** * @Author lyr * @create 2020/4/19 16:00 * 获取微信二维码的门票 * */@Data@Accessors(chain = true)public class ImageTicket { /** * 获取微信二维码门票的链接 */ public static final String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?" + "access_token=" + "%s"; /** * 获取微信二维码的门票 */ @JsonProperty("ticket") private String ticket; /** * 过期时间 */ @JsonProperty("expires_seconds") private Integer expireSeconds; /** * 返回给前端,让前端用这个 sceneId 轮询后端接口,确认是否用户已经登录 */ private String sceneId;}
用户登录状态实体(这里其实不用看的,你要什么业务,定义什么接口)
package com.example.mongodemo.framework.wechat.entity;import com.example.mongodemo.pojo.WeixinUserInfo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.RequiredArgsConstructor;import lombok.experimental.Accessors;/** * @Author lyr * @create 2020/4/19 15:29 */@Data@Accessors(chain = true)@AllArgsConstructorpublic class LoginUser { public static final String REDIS_KEY= "loginuser::"; private String sceneId; /** * 登录状态 */ private Boolean loginStatus = false; public LoginUser(String sceneId) { this.sceneId = sceneId; }}
请求接口,获取门票的配置
package com.example.mongodemo.framework.wechat.entity;import com.fasterxml.jackson.annotation.JsonProperty;import lombok.Data;import lombok.experimental.Accessors;/** * @Author lyr * @create 2020/4/19 16:20 */@Data@Accessors(chain = true)public class TicketRequest { public static final String REQUEST_TICKET_URL ="https://api.weixin.qq.com/cgi-bin/qrcode/create?" + "access_token=" + "%s" ; public static final String REQUEST_TEMPLATE ="{\n" + " \"expire_seconds\": 1800,\n" + " \"action_name\": \"QR_SCENE\",\n" + " \"action_info\": {\n" + " \"scene\": {\n" + " \"scene_str\": \"%s\"\n" + " }\n" + " }\n" + "}";}
wechatTemplate 的实现
package com.example.mongodemo.framework.wechat;import com.example.mongodemo.framework.wechat.entity.AccessToken;import com.example.mongodemo.framework.wechat.entity.ImageTicket;import com.example.mongodemo.framework.wechat.entity.LoginUser;import com.example.mongodemo.framework.wechat.entity.TicketRequest;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Component;import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;import java.time.Duration;/** * @Author lyr * @create 2020/4/19 11:31 */@Component@Slf4jpublic class RestWechatTemplate implements WechatTemplate{ /** * 获取 调用接口权限 的 ac token */ @Value("${wechatTemplate.getTicket.appid}") private String appId; /** * 密钥 */ @Value("${wechatTemplate.getTicket.secret}") private String secret; @Value("${wechatTemplate.getTicket.grant_type}") private String grantType; @Resource private RedisTemplateredisTemplate; /** * 远程调用 微信接口 */ @Resource private RestTemplate restTemplate; /** * @return 生成请求微信接口的 url => 请求 微信token的 url */ @Override public String generateTokenUrl() { String getBasicAccessToken = "https://api.weixin.qq.com/cgi-bin/" + "token?" + "grant_type=%s" + "&" + "appid=%s" + "&" + "secret=%s"; return String.format(getBasicAccessToken,grantType,appId,secret); // //log.info("微信返回结果 {}",responseString); // return responseString; } /** * 公众号每日 10000 次调用机会 * @return 返回 AccessToken */ @Deprecated public String getAccessToken() { String responseString = restTemplate .getForObject(generateTokenUrl(),String.class); return responseString; } /** * @return 请求微信接口,获得 AccessToken =》将 json传转对象 */ @Override public AccessToken getAccessTokenObject() { AccessToken token = (AccessToken) redisTemplate.opsForValue() .get(AccessToken.REDIS_KEY); if(token==null) { //请求微信 token = restTemplate.getForObject(generateTokenUrl(),AccessToken.class); if(token!=null) { //缓存 token 至有效时间 redisTemplate.opsForValue() .set(AccessToken.REDIS_KEY,token, Duration.ofSeconds(token.getExpiresIn()-10)); } } return token; } /** * 用户是否已经登录 * @param sceneId 场景id * @return */ @Override public LoginUser isUserLogin(String sceneId) { LoginUser loginUser = (LoginUser) redisTemplate .opsForValue() .get(LoginUser.REDIS_KEY); return loginUser==null ? new LoginUser(sceneId):loginUser; } /** * 用户是否已经登录 * @param sceneId 场景id * @return */ @Override public boolean userIsLogin(String sceneId) { return isUserLogin(sceneId).getLoginStatus(); } @Override public void setUserIsLogin(String sceneId) { redisTemplate.opsForValue() .set(LoginUser.REDIS_KEY+sceneId,new LoginUser(sceneId).setLoginStatus(true)); } @Override public ImageTicket getImageTicket() { String getTicketUrl = String .format(ImageTicket.GET_TICKET_URL, getAccessTokenObject() .getAccessTokenContent()); String sceneId = String.valueOf(System.nanoTime()); ResponseEntity responseEntity = restTemplate .postForEntity( //url getTicketUrl, //请求参数 String.format(TicketRequest.REQUEST_TEMPLATE, sceneId), ImageTicket.class ); ImageTicket ticket = responseEntity.getBody(); return ticket!=null?ticket.setSceneId(sceneId):null; } @Override public String generateQrCodeUrl(ImageTicket ticket) { String qrCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; return String.format(qrCodeUrl, ticket.getTicket()); }}
转载地址:http://hauzi.baihongyu.com/