|
- package chanjarster.weixin.service;
-
- import java.io.IOException;
- import java.nio.charset.Charset;
- import java.util.concurrent.atomic.AtomicBoolean;
-
- import org.apache.commons.lang3.StringUtils;
- import org.apache.http.client.ClientProtocolException;
- import org.apache.http.client.methods.CloseableHttpResponse;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.entity.StringEntity;
- import org.apache.http.impl.client.BasicResponseHandler;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.impl.client.HttpClients;
-
- import chanjarster.weixin.exception.WxErrorException;
- import chanjarster.weixin.in.WxAccessToken;
- import chanjarster.weixin.in.WxError;
- import chanjarster.weixin.out.WxCustomMessage;
- import chanjarster.weixin.out.WxMenu;
-
- public class WxServiceImpl implements WxService {
-
- /**
- * 全局的是否正在刷新Access Token的flag
- * true: 正在刷新
- * false: 没有刷新
- */
- protected static final AtomicBoolean GLOBAL_ACCESS_TOKEN_REFRESH_FLAG = new AtomicBoolean(false);
-
- protected static final CloseableHttpClient httpclient = HttpClients.createDefault();
-
- protected static final Charset UTF8 = Charset.forName("UTF-8");
-
- protected WxConfigProvider wxConfigProvider;
-
- /**
- * 获得access_token
- * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
- * @return
- * @throws WxErrorException
- */
- public void refreshAccessToken() throws WxErrorException {
- if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) {
- try {
- String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
- + "&appid=" + wxConfigProvider.getAppId()
- + "&secret=" + wxConfigProvider.getSecret()
- ;
- try {
- HttpGet httpGet = new HttpGet(url);
- CloseableHttpResponse response = httpclient.execute(httpGet);
- String resultContent = new BasicResponseHandler().handleResponse(response);
- WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
- wxConfigProvider.updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in());
- } catch (ClientProtocolException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- } finally {
- GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.set(false);
- }
- } else {
- // 每隔100ms检查一下是否刷新完毕了
- while (GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.get()) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- }
- }
- // 刷新完毕了,就没他什么事儿了
- }
- }
-
- /**
- * 发送客服消息
- * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
- * @param message
- * @throws WxErrorException
- */
- public String sendCustomMessage(WxCustomMessage message) throws WxErrorException {
- String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
- return post(url, message.toJson());
- }
-
- protected String post(String uri, String data) throws WxErrorException {
- return execute("POST", uri, data);
- }
-
- protected String get(String uri, String data) throws WxErrorException {
- return execute("GET", uri, data);
- }
-
- /**
- * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
- * @param request
- * @return 微信服务端返回的结果
- * @throws WxErrorException
- */
- protected String execute(String method, String uri, String data) throws WxErrorException {
- if (StringUtils.isBlank(wxConfigProvider.getAccessToken())) {
- refreshAccessToken();
- }
- String accessToken = wxConfigProvider.getAccessToken();
-
- String uriWithAccessToken = uri;
- uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;
-
- try {
- String resultContent = null;
- if ("POST".equals(method)) {
- HttpPost httpPost = new HttpPost(uriWithAccessToken);
- StringEntity entity = new StringEntity(data, UTF8);
- httpPost.setEntity(entity);
- CloseableHttpResponse response = httpclient.execute(httpPost);
- resultContent = new BasicResponseHandler().handleResponse(response);
- } else if ("GET".equals(method)) {
- HttpGet httpGet = new HttpGet(uriWithAccessToken);
- CloseableHttpResponse response = httpclient.execute(httpGet);
- resultContent = new BasicResponseHandler().handleResponse(response);
- }
-
- WxError error = WxError.fromJson(resultContent);
- /*
- * 关于微信返回错误码 详情请看 http://mp.weixin.qq.com/wiki/index.php?title=全局返回码说明
- * 40001 微信图片不对
- * 42001 access_token超时
- */
- if (error.getErrcode() == 42001 || error.getErrcode() == 40001) {
- refreshAccessToken();
- return execute(method, uri, data);
- }
- if (error.getErrcode() != 0) {
- throw new WxErrorException(error);
- }
- return resultContent;
- } catch (ClientProtocolException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- *
- * @param menu
- * @throws WxErrorException
- */
- public String createMenu(WxMenu menu) throws WxErrorException {
- // TODO
- return null;
- }
-
- /**
- *
- * @throws WxErrorException
- */
- public String deleteMenu() throws WxErrorException {
- // TODO
- return null;
- }
-
- /**
- *
- * @return
- * @throws WxErrorException
- */
- public WxMenu getMenu() throws WxErrorException {
- // TODO
- return null;
- }
-
- public void setWxConfigProvider(WxConfigProvider wxConfigProvider) {
- this.wxConfigProvider = wxConfigProvider;
- }
-
- }
|