手写一个生成带参数 微信二维码的工具类
程序员文章站
2022-04-23 23:40:14
...
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
*/
@Data
public 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)
@AllArgsConstructor
public 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
@Slf4j
public 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 RedisTemplate<String, Object> redisTemplate;
/**
* 远程调用 微信接口
*/
@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<ImageTicket> 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());
}
}
上一篇: 对你服务的异常做详细的划分
下一篇: MySQL多实例搭建