前段时间在公司根据客户需求做微信公众号的开发,客户需求之一就是,接入后台同时支持多个公众号运行。
- 微信配置参数切换
- AccessToken入库存储
此前读者需了解System系统类和Environment,详情请查阅笔者System系统类和Environment环境抽象博文
WxConfig微信基本参数配置类,需单例
package com.bigbigbu.wx.tools.api;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import com.bigbigbu.wx.tools.bean.WxAccessToken;
import com.bigbigbu.wx.tools.exception.WxErrorException;
import com.bigbigbu.wx.tools.util.StringUtils;
/**
* Title: WxAccessToken
* Description: 微信全局配置对象-从配置文件读取,原作者antgan于2016/12/14码
* Company: BIGBIGBU
* @author FANQIBU
* @date 2017年12月7日
*/
public class WxConfig {
private static final String configFile = "/wx.properties";//默认加载resources下的wx配置文件
private static WxConfig config = null;
//配置文件读取项
private volatile String appId;
private volatile String appSecret;
private volatile String token;
private volatile String aesKey;
private volatile String mchId;
private volatile String apiKey;
//内存更新
private volatile String accessToken;
private volatile long expiresTime;
private volatile String jsapiTicket;
private volatile long jsapiTicketExpiresTime;
//多公众号模式下自定义系统回调
private IWxManySysService wxManySysService;
/**
* @Title: WxConfig
* @Description: FANQIBU 动态加载配置文件
* @param:
* @throws
*/
public WxConfig() {
//写读配置文件代码
Properties p = new Properties();
InputStream inStream = this.getClass().getResourceAsStream(configFile);
if(inStream == null){
try {
throw new WxErrorException("根目录找不到文件");
} catch (WxErrorException e) {
e.printStackTrace();
}
}
try {
p.load(inStream);
if(StringUtils.isEmpty(System.getProperty("wx.appId"))){
this.appId = p.getProperty("wx.appId");
}else{
this.appId = System.getProperty("wx.appId");
}
if(StringUtils.isNotBlank(this.appId)) this.appId = this.appId.trim();
if(StringUtils.isEmpty(System.getProperty("wx.appSecret"))){
this.appSecret = p.getProperty("wx.appSecret");
}else{
this.appSecret = System.getProperty("wx.appSecret");
}
if(StringUtils.isNotBlank(this.appSecret)) this.appSecret = this.appSecret.trim();
if(StringUtils.isEmpty(System.getProperty("wx.token"))){
this.token = p.getProperty("wx.token");
}else{
this.token = System.getProperty("wx.token");
}
if(StringUtils.isNotBlank(this.token)) this.token = this.token.trim();
if(StringUtils.isEmpty(System.getProperty("wx.aesKey"))){
this.aesKey = p.getProperty("wx.aesKey");
}else{
this.aesKey = System.getProperty("wx.aesKey");
}
if(StringUtils.isNotBlank(this.aesKey)) this.aesKey = this.aesKey.trim();
if(StringUtils.isEmpty(System.getProperty("wx.mchId"))){
this.mchId = p.getProperty("wx.mchId");
}else{
this.mchId = System.getProperty("wx.mchId");
}
if(StringUtils.isNotBlank(this.mchId)) this.mchId = this.mchId.trim();
if(StringUtils.isEmpty(System.getProperty("wx.apiKey"))){
this.apiKey = p.getProperty("wx.apiKey");
}else{
this.mchId = System.getProperty("wx.apiKey");
}
if(StringUtils.isNotBlank(this.apiKey)) this.apiKey = this.apiKey.trim();
if(!StringUtils.isEmpty(System.getProperty("wx.accessToken"))){
this.accessToken = System.getProperty("wx.accessToken");
}
if(!StringUtils.isEmpty(System.getProperty("wx.expiresTime"))){
this.expiresTime = Long.parseLong(System.getProperty("wx.expiresTime"));
}
inStream.close();
} catch (IOException e) {
try {
throw new WxErrorException("load wx.properties error,class根目录下找不到wx.properties文件");
} catch (WxErrorException e1) {
e1.printStackTrace();
}
}
System.out.println("load wx.properties success");
System.out.println(this.toString());
}
/**
* 同步获取/加载单例
* @return
*/
public static synchronized WxConfig getInstance(){
if(config == null){
config = new WxConfig();
}
return config;
}
/**
* 同步获取/加载单例
* @return
*/
public static synchronized void refreshInstance(){
config = new WxConfig();
}
public String getAccessToken() {
return accessToken;
}
public boolean isAccessTokenExpired() {
return System.currentTimeMillis() > this.expiresTime;
}
public void expireAccessToken() {
this.expiresTime = 0;
}
/**
* Title: updateAccessToken
* Description: 更新接口调用凭证
* @param WxAccessToken accessToken
* @param boolean isCallback 是否调用系统回调
*/
public synchronized void updateAccessToken(WxAccessToken accessToken,boolean isCallback) {
updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in(),isCallback);
}
/**
* Title: updateAccessToken
* Description: FANQIBU修改更新接口调用凭证
* @param String accessToken
* @param long expiresInSeconds
* @param boolean isCallback 是否调用系统回调
*/
public synchronized void updateAccessToken(String accessToken, long expiresInSeconds,boolean isCallback) {
this.accessToken = accessToken;
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
//调用微信WxSysCallback
if(this.getWxManySysService()!=null && isCallback){
//微信刷新access_token接口调用凭证回调(PS:针对多公众号情况下access_token更新入库操作)
this.getWxManySysService().wxAccessTokenCallback(this.accessToken, this.expiresTime);
}
}
public String getJsapiTicket() {
return jsapiTicket;
}
public void setJsapiTicket(String jsapiTicket) {
this.jsapiTicket = jsapiTicket;
}
public long getJsapiTicketExpiresTime() {
return jsapiTicketExpiresTime;
}
public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) {
this.jsapiTicketExpiresTime = jsapiTicketExpiresTime;
}
public boolean isJsapiTicketExpired() {
return System.currentTimeMillis() > this.jsapiTicketExpiresTime;
}
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
this.jsapiTicket = jsapiTicket;
// 预留200秒的时间
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
}
public void expireJsapiTicket() {
this.jsapiTicketExpiresTime = 0;
}
//getter
public String getAppId() {
return appId;
}
public String getAppSecret() {
return appSecret;
}
public String getToken() {
return token;
}
public String getAesKey() {
return aesKey;
}
public String getMchId() {
return mchId;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public IWxManySysService getWxManySysService() {
return wxManySysService;
}
public void setWxManySysService(IWxManySysService wxManySysService) {
this.wxManySysService = wxManySysService;
}
@Override
public String toString() {
return "WxConfig [appId=" + appId + ", appSecret=" + appSecret + ", token=" + token + ", aesKey=" + aesKey
+ ", mchId=" + mchId + ", apiKey=" + apiKey + ", accessToken=" + accessToken + ", expiresTime="
+ expiresTime + ", jsapiTicket=" + jsapiTicket + ", jsapiTicketExpiresTime=" + jsapiTicketExpiresTime
+ "]";
}
}
定义接口IWxManySysService 主要作用多公众号模式下动态加载配置信息和接口调用凭证access_token更新
package com.bigbigbu.wx.tools.api;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.bigbigbu.wx.tools.bean.WxAccessToken;
import com.bigbigbu.wx.tools.bean.many.WxBaseConfig;
import com.bigbigbu.wx.tools.util.StringUtils;
/**
* Title: IWxManySysService
* Description: 多公众号模式下动态加载配置信息和接口调用凭证access_token更新
* Company: DINGGE
* @author FANQIBU
* @date 2017年12月7日
*/
public interface IWxManySysService {
/**
* Title: wxAccessTokenCallback
* Description: 微信刷新access_token接口调用凭证回调(PS:一般针对多公众号情况下access_token更新入库操作)
* @param accessToken
* @param expiresInSeconds
*/
public void wxAccessTokenCallback(String accessToken, long expiresInSeconds);
/**
* Title: loadWxProperties
* Description:多公众号动态加载微信配置参数
* @param String wxsystoken 本地系统wx令牌(从数据库查找当前公众号配置参数)
*/
public default boolean loadWxProperties(String newwxsystoken,String oldwxsystoken,String oldappId,String oldappSecret,
String oldtoken,String oldaesKey,String oldmchid,String oldapiKey){
if(StringUtils.isEmpty(newwxsystoken)){
return false;
}
try {
Map parmer=new HashMap<>();
parmer.put("wxsystoken", newwxsystoken);
//根据系统公众号token获取公众号配置信息
List configs=this.listWxbaseConfig(parmer);
if(configs != null && configs.size()>0){
if(configs.get(0).appid!=null && !configs.get(0).appid.equals(oldappId))
System.setProperty("wx.appId",configs.get(0).appid);
if(configs.get(0).appsecret!=null && !configs.get(0).appsecret.equals(oldappSecret))
System.setProperty("wx.appSecret",configs.get(0).appsecret);
if(configs.get(0).token!=null && !configs.get(0).token.equals(oldtoken))
System.setProperty("wx.token",configs.get(0).token);
if(configs.get(0).encodingaeskey!=null && !configs.get(0).encodingaeskey.equals(oldaesKey)){
System.setProperty("wx.aesKey",configs.get(0).encodingaeskey);
}
if(configs.get(0).mchid!=null && !configs.get(0).mchid.equals(oldmchid)){
System.setProperty("wx.mchId",configs.get(0).mchid);
}
if(configs.get(0).apiKey!=null && !configs.get(0).apiKey.equals(oldapiKey)){
System.setProperty("wx.apiKey",configs.get(0).apiKey);
}
System.setProperty("wx.gz.id",configs.get(0).gzid+"");
System.setProperty("wx.gz.remark",configs.get(0).remark);
if(!newwxsystoken.equals(oldwxsystoken)){
System.setProperty("wx.wxsystoken",configs.get(0).wxsystoken);
}
//查询数据库token数据
WxAccessToken accessToken=this.getWeixinAccessToken(parmer);
if(accessToken != null){
System.setProperty("wx.accessToken",accessToken.getAccess_token());
System.setProperty("wx.expiresTime",accessToken.getExpires_in()+"");
}
WxConfig.refreshInstance();
WxConfig.getInstance().setWxManySysService(this);
}else{
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public List listWxbaseConfig(Map parmer);
public WxAccessToken getWeixinAccessToken(Map parmer);
}
接口实现
package com.lh.wx.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import com.lh.wx.dao.WeixinAccessTokenMapper;
import com.lh.wx.dao.WeixinConfigMapper;
import com.lh.wx.model.WeixinAccessTokenDto;
import com.lh.wx.servlet.InitServlet;
import com.bigbigbu.wx.tools.api.IWxManySysService;
import com.bigbigbu.wx.tools.bean.WxAccessToken;
import com.bigbigbu.wx.tools.bean.many.WxBaseConfig;
/**
* Title: WxSysCallback
* Description: 自定义系统回调
* Company: DINGGE
* @author FANQIBU
* @date 2017年12月7日
*/
@Service
public class WxManySysService implements IWxManySysService{
private @Inject WeixinConfigMapper weixinConfigMapper;
private @Inject WeixinAccessTokenMapper weixinAccessTokenMapper;
private @Inject Environment environment;
@Override
public void wxAccessTokenCallback(String accessToken, long expiresInSeconds) {
String wxsystoken=environment.getProperty("wx.wxsystoken");
Map parmer=new HashMap<>();
parmer.put("wxsystoken", wxsystoken);
List accessTokenDtos=weixinAccessTokenMapper.listWeixinAccessToken(parmer);
WxAccessToken wxAccessToken=new WxAccessToken();
wxAccessToken.setAccess_token(accessToken);
wxAccessToken.setExpires_in(expiresInSeconds);
if(accessTokenDtos != null && accessTokenDtos.size()>0){
WeixinAccessTokenDto resultDto=accessTokenDtos.get(0);
resultDto.setAccessToken(wxAccessToken);
weixinAccessTokenMapper.upWeixinAccessToken(resultDto);
}else{
WeixinAccessTokenDto resultDto=new WeixinAccessTokenDto();
resultDto.setWxsystoken(wxsystoken);
resultDto.setAccessToken(wxAccessToken);
weixinAccessTokenMapper.addWeixinAccessToken(resultDto);
}
}
@Override
public List listWxbaseConfig(Map parmer) {
WxBaseConfig wxBaseConfig=InitServlet.wxBaseConfig.get(parmer.get("wxsystoken"));
if(wxBaseConfig != null){
List wxBaseConfigs =new ArrayList<>();
wxBaseConfigs.add(wxBaseConfig);
return wxBaseConfigs;
}
return weixinConfigMapper.listWeixinConfig(parmer);
}
@Override
public WxAccessToken getWeixinAccessToken(Map parmer) {
List accessTokenDtos=weixinAccessTokenMapper.listWeixinAccessToken(parmer);
if(accessTokenDtos != null && accessTokenDtos.size()>0){
//int expires_in =new Long((System.currentTimeMillis() - accessTokenDtos.get(0).getUpdatetime().getTime())/1000).intValue();
//accessTokenDtos.get(0).getAccessToken().setExpires_in(expires_in);
return accessTokenDtos.get(0).getAccessToken();
}
return null;
}
}
package com.lh.wx.service;
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
@Service
public class WechatService {
private @Inject Environment environment;
private @Inject WxManySysService wxManySysService;
public boolean loadWxSysConfigure(String wxsystoken,boolean isMust){
if(!StringUtils.isEmpty(wxsystoken)){
return wxManySysService.loadWxProperties(wxsystoken,environment.getProperty("wx.wxsystoken"),environment.getProperty("wx.appId")
,environment.getProperty("wx.appSecret"),environment.getProperty("wx.token"),environment.getProperty("wx.aesKey")
,environment.getProperty("wx.mchId"),environment.getProperty("wx.apiKey"));
}
if(isMust){
return false;
}
return true;
}
}