步骤为 ->
1.先向wx(后称为第三方)拿:access_token ->
2.使用拿到的access_token 去获取 自己公众号中的已关注的每个用户的openId ->
3.依据openId 给每个用户发送模板信息。
具体细节可查看官方文档
第一步:
@Component
public class PushAccessTokenTool {
private static Logger log = Logger.getLogger(PushAccessTokenTool.class);
public static final String AppId = "AppId";
public static final String AppSecret = "AppSecret";
public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ AppId + "&secret=" + AppSecret;
public static String access_token = "";
public static String ACCESS_TOKEN_C8_XCXAPI = "access_token_c8_wchPush"; //Redis存储accesstoken
/**
* 过期时间7200秒, 因为微信token过期时间为2小时,即7200秒
*/
private static int expireTime = 7200 * 1000;
private static TimeUnit refreshTime = TimeUnit.MILLISECONDS;
private static RedisManager redisManager;
@Autowired
private RedisManager redisManager1;
@PostConstruct
public void beforeInit() {
redisManager = redisManager1;
}
/**
* 获取微信accesstoken
*
* @return
*/
public static synchronized String getAccessToken() {
return getAccessToken(false);
}
public static synchronized String afreshAccessToken() {
redisManager.delete(ACCESS_TOKEN_C8_XCXAPI);
return getAccessToken(false);
}
public static synchronized String getAccessToken(boolean refresh) {
access_token = (String) redisManager.getValue(ACCESS_TOKEN_C8_XCXAPI);
if (StringUtils.isBlank(access_token) || refresh) {
PushAccessTokenTool.access_token = initAccessToken();
}
return access_token;
}
private static String initAccessToken() {
String responseContent = HttpUtil.sendGet(GET_ACCESS_TOKEN_URL);
JSONObject object = new JSONObject();
try {
object = new JSONObject(responseContent);
String access_token = (String) object.get("access_token");
redisManager.saveForValue(ACCESS_TOKEN_C8_XCXAPI,access_token,expireTime, refreshTime);
log.info("access_token重新刷新成功:"+access_token);
return access_token;
} catch (JSONException e) {
try {
log.error("获取token失败 errcode:" + object.get("errcode") + " errmsg:" + object.getString("errmsg"));
} catch (JSONException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
return null;
}
}
HttpUtil:
public class HttpUtil {
private static final CloseableHttpClient httpclient = HttpClients.createDefault();
/**
* 发送HttpGet请求
* @param url
* @return
*/
public static String sendGet(String url) {
HttpGet httpget = new HttpGet(url);
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpget);
} catch (IOException e1) {
e1.printStackTrace();
}
String result = null;
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity);
}
} catch (ParseException | IOException e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
RedisManager :
public class RedisManager {
private RedisTemplate<String,Object> redisTemplate;
private StringRedisTemplate stringRedisTemplate;
private TimeUnit timeUnit;
private long expired;
/**
* 保存为值
* @param key
* @param val
*/
public void saveForValue(String key,Object val) {
redisTemplate.opsForValue().set(key, val,expired, timeUnit);
}
public void saveForValue(String key, Object val, long expired, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, val,expired, timeUnit);
}
/**
* 从value中获取值
* @param key
* @return
*/
public Object getValue(String key) {
return redisTemplate.opsForValue().get(key);
}
@Deprecated
public void saveForValueByStr(String key,String value) {
stringRedisTemplate.opsForValue().set(key, value, expired, timeUnit);
}
public void saveForList(List<?> list,String key) {
}
public void saveForMap(Object val,String key,String hashKey) {
redisTemplate.opsForHash().put(key, hashKey, val);
redisTemplate.expire(key, expired, timeUnit);
}
public Object getFromMap(String key,String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
}
public long getExpired() {
return expired;
}
public void setExpired(long expired) {
this.expired = expired;
}
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
public void delete(String key) {
redisTemplate.delete(key);
}
}
第二步:
/**
* 获取微信公众号关注用户
* 官方接口文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/Getting_a_User_List.html
* @param access_token
* @return
*/
public static Set<String> getUsers(String access_token) {
String usersGetUrl="https://api.weixin.qq.com/cgi-bin/user/get";
usersGetUrl+="?access_token="+access_token;
JSONObject data=getUrlResponse(usersGetUrl);
Set<String>openIds=new HashSet<String>();
Integer total=0,count=0;
try {
total=(Integer) data.get("total");
count=(Integer) data.get("count");
//总关注用户数超过默认一万
if(count<total){
openIds.addAll(getUsers(openIds,usersGetUrl, access_token, (String)data.get("next_openid")));
}else{
//有关注者 json才有data参数
if(count>0){
JSONObject openIdData=(JSONObject) data.get("data");
JSONArray openIdArray= (JSONArray) openIdData.get("openid");
for(int i=0;i<openIdArray.length();i++){
openIds.add((String) openIdArray.get(i));
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return openIds;
}
private static JSONObject getUrlResponse(String url) {
CharsetHandler handler = new CharsetHandler("UTF-8");
try {
HttpGet httpget = new HttpGet(new URI(url));
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
//HttpClient
CloseableHttpClient client = httpClientBuilder.build();
client = (CloseableHttpClient) wrapClient(client);
return new JSONObject(client.execute(httpget, handler));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static class CharsetHandler implements ResponseHandler<String> {
private String charset;
public CharsetHandler(String charset) {
this.charset = charset;
}
public String handleResponse(HttpResponse response)
throws ClientProtocolException, IOException {
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() >= 300) {
throw new HttpResponseException(statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
HttpEntity entity = response.getEntity();
if (entity != null) {
if (!StringUtils.isBlank(charset)) {
return EntityUtils.toString(entity, charset);
} else {
return EntityUtils.toString(entity);
}
} else {
return null;
}
}
}
private static HttpClient wrapClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("TLSv1");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{
tm}, null);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(ctx, new String[]{
"TLSv1"}, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
return httpclient;
} catch (Exception ex) {
return null;
}
}
private static Set<String> getUsers(Set<String> openIds, String url, String access_token, String next_openid) {
JSONObject data=getUrlResponse(url);
try {
Integer count=(Integer) data.get("count");
String nextOpenId=(String) data.get("next_openid");
if(count>0){
JSONObject openIdData=(JSONObject) data.get("data");
JSONArray openIdArray= (JSONArray) openIdData.get("openid");
for(int i=0;i<openIdArray.length();i++){
openIds.add((String) openIdArray.get(i));
}
}
if(StringUtils.isNotBlank(nextOpenId)){
return getUsers(openIds,url, access_token, nextOpenId);
}
} catch (JSONException e) {
e.printStackTrace();
}
return openIds;
}