123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- package com.nuliji.tools.third.wechat;
- import com.alibaba.fastjson.JSONObject;
- import com.nuliji.tools.Tools;
- import com.nuliji.tools.third.OauthData;
- import org.apache.commons.lang.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.http.HttpEntity;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.MediaType;
- import org.springframework.stereotype.Component;
- import org.springframework.stereotype.Service;
- import org.springframework.web.client.RestTemplate;
- import java.net.URLEncoder;
- import java.sql.Time;
- import java.util.*;
- public class WechatClient {
- private static final Logger logger = LoggerFactory.getLogger(WechatClient.class);
- private String appId = "";
- private String appSecret = "";
- public WechatClient(String appId, String appSecret){
- this.appId = appId;
- this.appSecret = appSecret;
- }
- private static Map<String, String> tokenMap = new HashMap<>();
- private static Map<String, Date> tokenExpiresIn = new HashMap<>();
- private static Map<String, String> jsTicketMap = new HashMap<>();
- private static Map<String, Date> jsTicketExpiresIn = new HashMap<>();
- /**
- * 从微信服务器获取临时访问二维码
- *
- */
- public String getQrcode(int sceneId) {
- String accessToken = getAccessToken(appId, appSecret);
- String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
- Map<String, Object> body = new HashMap<>();
- body.put("expire_seconds", 3600);
- body.put("action_name", "QR_SCENE");
- Map<String, Object> actionInfo = new HashMap<>();
- Map<String, Object> scene = new HashMap<>();
- scene.put("scene_id", sceneId);
- actionInfo.put("scene", scene);
- body.put("action_info", actionInfo);
- JSONObject object = execute(url, null, body);
- return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + object.getString("ticket");
- }
- public String getOAuthUrl(String redirectUrl ,String state){
- return "https://open.weixin.qq.com/connect/qrconnect?appid="+appId+"&redirect_uri="+redirectUrl+"&response_type=code&scope=snsapi_login&state="+state+"#wechat_redirect";
- }
- /**
- * 取微信公众平台accesstoken
- *
- * @return
- */
- private static synchronized String getAccessToken(String appid, String secret) {
- Date date = new Date();
- // 系统刚启动时,或者离上次取accessToken有7180秒以上时,重新取它
- if (!tokenMap.containsKey(appid) || date.getTime() / 1000 - tokenExpiresIn.get(appid).getTime() / 1000 >= 7180) {
- Map<String, String> params = new HashMap<>();
- params.put("grant_type", "client_credential");
- params.put("appid", appid);
- params.put("secret", secret);
- JSONObject object = execute("https://api.weixin.qq.com/cgi-bin/token", params, null);
- tokenMap.put(appid, object.getString("access_token"));
- tokenExpiresIn.put(appid, date);
- logger.info("getAccessToken:" + tokenMap.get(appid));
- }
- return tokenMap.get(appid);
- }
- /**
- * 取微信公众平台js_ticket
- *
- * @return
- */
- private static synchronized String getJSTicket(String appid, String secret) {
- String accessToken = getAccessToken(appid, secret);
- Date date = new Date();
- // 系统刚启动时,或者离上次取accessToken有7180秒以上时,重新取它
- if (!jsTicketMap.containsKey(accessToken) || date.getTime() / 1000 - jsTicketExpiresIn.get(accessToken).getTime() / 1000 >= 7180) {
- Map<String, String> params = new HashMap<>();
- params.put("access_token", accessToken);
- params.put("type", "jsapi");
- JSONObject object = execute("https://api.weixin.qq.com/cgi-bin/ticket/getticket", params, null);
- jsTicketMap.put(accessToken, object.getString("ticket"));
- jsTicketExpiresIn.put(accessToken, date);
- logger.info("getJSTicket:" + jsTicketMap.get(accessToken));
- }
- return jsTicketMap.get(accessToken);
- }
- private JSONObject getWebAccessToken(String code) {
- Map<String, String> params = new HashMap<>();
- params.put("appid", appId);
- params.put("secret", appSecret);
- params.put("code", code);
- params.put("grant_type", "authorization_code");
- JSONObject object = execute("https://api.weixin.qq.com/sns/oauth2/access_token", params, null);
- return object;
- }
- public OauthData webAuthorize(String code) {
- JSONObject result = getWebAccessToken(code);
- // 从result中解析出openid和session
- if (result.get("errcode") != null) {
- logger.warn(String.format("jscodeToSession failed: result = %s", result));
- throw new RuntimeException(String.format("从微信服务器换取用户登录态信息: 错误码: %d, 错误信息: %s", result.getIntValue("errcode"), result.getString("errmsg")));
- }
- JSONObject info = getWebUserInfo(result.getString("access_token"), result.getString("openid"));
- OauthData data = new OauthData();
- data.setRefreshToken(result.getString("refresh_token"));
- data.setAccessToken(result.getString("access_token"));
- data.setExpiresTime(new Date(new Date().getTime() + result.getInteger("expires_in")));
- data.setAvatar(info.getString("avatar"));
- data.setNickName(info.getString("nickname"));
- data.setUnionId(info.getString("unionid"));
- data.setOpenId(info.getString("openid"));
- data.setGender(info.getIntValue("sex") == 1 ? "mela":"femela");
- return data;
- }
- public JSONObject getWebUserInfo(String accessToken, String openid) {
- Map<String, String> params = new HashMap<>();
- params.put("access_token", accessToken);
- params.put("openid", openid);
- params.put("lang", "zh_CN");
- JSONObject object = execute("https://api.weixin.qq.com/sns/userinfo", params, null);
- return object;
- }
- public OauthData refreshWebAccessToken(String refreshToken){
- Map<String, String> params = new HashMap<>();
- params.put("appid", appId);
- params.put("refresh_token", refreshToken);
- params.put("grant_type", "refresh_token");
- JSONObject result = execute("https://api.weixin.qq.com/sns/oauth2/refresh_token", params, null);
- OauthData data = new OauthData();
- data.setRefreshToken(result.getString("refresh_token"));
- data.setAccessToken(result.getString("access_token"));
- data.setExpiresTime(new Date(new Date().getTime() + result.getInteger("expires_in")));
- return data;
- }
- public String jsTicket(){
- return getJSTicket(appId, appSecret);
- }
- /**
- * 处理接收到的微信消息
- *
- * @param request
- * @param listener
- * @return
- */
- public void ReceiveMessage(String request, MessageListener listener) {
- logger.info("receive -------------------------------------- = " + request);
- TreeMap<String, String> map = Tools.parseXml(request);
- if (map == null) {
- logger.warn("processReceiveWeixinMessage(): request is null");
- return ;
- }
- String openId = map.get("FromUserName");
- if (openId == null) {
- logger.error("processReceiveWeixinMessage(): FromUserName(openid) error: " + request);
- return;
- }
- // 已关注
- // 未关注进行关注
- if ("event".equals(map.get("MsgType")) && "SCAN".equals(map.get("Event"))) {
- // 后台根据场景值A,查询到对应的用户ID
- int sceneId = Integer.valueOf(map.get("EventKey"));
- listener.OnScan(openId, sceneId);
- } else if ("event".equals(map.get("MsgType")) && "subscribe".equals(map.get("Event"))) {
- // 关注事件-普通关注事件
- if (StringUtils.isBlank(map.get("EventKey"))) {
- listener.OnSubscribe(openId);
- }
- else if (map.get("EventKey").startsWith("qrscene_")) // 关注事件-扫描带参数二维码事件(内部帐号绑定微信号)
- {
- // 后台根据场景值A,查询到对应的用户ID
- int sceneId = Integer.valueOf(map.get("EventKey").substring("qrscene_".length()));
- listener.OnSubscribe(openId);
- listener.OnScan(openId, sceneId);
- }
- }
- }
- /**
- * 公众号发送微信消息给指定商家
- *
- * @param openid
- * @param templateId
- * @param dataUrl
- * @param dataMap
- * @return 返回数据,正常返回的例子: {"errcode":0,"errmsg":"ok","msgid":200228332}
- */
- public JSONObject sendMessage(String openid, String templateId, String dataUrl, Map<String, String> dataMap) {
- String accessToken = getAccessToken(appId, appSecret);
- String url = "https://api.weixin.qq.com/cgi-bin/message/template/send";
- Map<String, String> params = new HashMap<>();
- params.put("access_token", accessToken);
- Map<String, Object> body = new HashMap<>();
- body.put("touser", openid);
- body.put("template_id", templateId);
- if (dataUrl != null){
- body.put("url", dataUrl);
- }
- body.put("data", dataMap);
- JSONObject object = execute(url, params, body);
- return object;
- }
- public JSONObject sendCustomMessage(String openid, String content) {
- String accessToken = getAccessToken(appId, appSecret);
- String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
- Map<String, String> params = new HashMap<>();
- params.put("access_token", accessToken);
- HttpHeaders headers = new HttpHeaders();
- Map<String, Object> body = new HashMap<>();
- body.put("touser", openid);
- body.put("msgtype", "text");
- Map<String, Object> text = new HashMap<>();
- text.put("content", content);
- body.put("text", text);
- body.put("data", null);
- JSONObject object = execute(url, params, body);
- return object;
- }
- private static JSONObject execute(String api, Map<String, String> urlParams, Map<String,Object> bodyParams) throws RuntimeException {
- try {
- String paramStr = "";
- if (urlParams != null){
- List<String> keys = new ArrayList<>(urlParams.keySet());
- Collections.sort(keys);
- for (int i = 0; i < keys.size(); i++) {
- String key = keys.get(i);
- String value = urlParams.get(key);
- value = URLEncoder.encode(value, "UTF-8");
- if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
- paramStr = paramStr + key + "=" + value;
- } else {
- paramStr = paramStr + key + "=" + value + "&";
- }
- }
- }
- HttpHeaders headers = new HttpHeaders();
- MediaType type = MediaType.APPLICATION_JSON;
- headers.setContentType(type);
- RestTemplate restTemplate = new RestTemplate();
- String result ="";
- if (bodyParams == null){
- result = restTemplate.getForObject(api+"?"+paramStr, String.class);
- } else {
- HttpEntity<String> formEntity = new HttpEntity<>(JSONObject.toJSONString(bodyParams), headers);
- result = restTemplate.postForObject(api+ "?" + paramStr, formEntity, String.class);
- }
- logger.info("微信返回结果:" + result);
- JSONObject a = JSONObject.parseObject(result);
- if(a.getInteger("errcode") !=null && a.getInteger("errcode") > 0){
- throw new Exception("接口错误"+a.getString("errmsg"));
- }
- return a;
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
- }
|