网页授权获取用户基本信息---获取code码
今天碰到微信公众号实现菜单跳转请求用户参数
获取code码碰到了这个问题
网页微信第三方登录-redirect_uri参数错误
通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)
目录
2 第二步:通过code换取网页授权access_token
4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
第一步:用户同意授权,获取code
在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。
尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问
参考链接(请在微信客户端中打开此链接体验):
scope为snsapi_base
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect
scope为snsapi_userinfo
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
尤其注意:跳转回调redirect_uri,应当使用https链接来确保授权code的安全性。
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 公众号的唯一标识 |
redirect_uri | 是 | 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) |
state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 |
#wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 |
注意:其中redirect_uri必须到http://tool.chinaz.com/tools/urlencode.aspx把你要请求的地址转urlEncode码然后请求
用户同意授权后
如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
code说明 : code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
我的链接转码过前为:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx7f1ceeace0d20918&redirect_uri=https://bw.cross.echosite.cn/shjz/people!addPeople213.do&code=CODE&scope=snsapi_userinfo&state=1&connect_redirect=1#wechat_redirect
我的链接转码过后为:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx7f1ceeace0d20918&redirect_uri=https%3a%2f%2fbw.cross.echosite.cn%2fshjz%2fpeople!addPeople213.do&code=CODE&scope=snsapi_userinfo&state=1&connect_redirect=1#wechat_redirect
发送到微信点开第一步
然后参数到了后台
其中addPeople213这个方法不能带参数否则会报错,然后在方法体中接收code码就ok了
到此code码就获取到了
wechatUtil.java工具类
package com.tlzn.util.Tencent; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.net.ssl.HttpsURLConnection; import org.apache.struts2.ServletActionContext; import org.apache.commons.lang.StringUtils; import org.springframework.web.client.RestTemplate; import com.alibaba.fastjson.JSONObject; import com.tlzn.util.base.Constants; import com.tlzn.util.base.DateFormatTools; import com.tlzn.util.base.Util; import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; /** * 发送微信消息工具类 * @author wjy * */ public class WechatUtil { static Util util=Util.getInstance(); static DateFormatTools DateUtil=DateFormatTools.getInstance(); /** * 服务类目为:“IT科技 > 软件服务提供商 > 服务完成通知”的模板ID */ private static String SERVICE_CATEGORY_IT_SOFTWARE_SERVICE_SUCCESS = "fEM1jg0ZOWZ9LfVVSzmKI7iIcJpJdiM5TTnuq1qQXSA"; /** * 用于存放所有学校的access_token信息,便于统一管理,并且每2小时需要重新刷新一次 */ public static Map<String, Object> allAccessTokenMap = new HashMap<String, Object>(); private static final String REQUEST_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; /** * 获取/刷新accessToken url地址 */ private static final String REQUEST_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code"; /** * 网页端引用微信js请求授权url */ private static final String REQUEST_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token="; /** * 微信发送客服消息接口url */ private static final String SEND_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="; /** * 微信公众号发送订阅通知 */ private static final String SEND_MSG_SUBSCRIBE_BIZSEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token="; private static final String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="; private static final String REQUEST_WECHAT_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?lang=zh_CN"; private static final String REQUEST_WECHAT_FACEINFO_URL = "https://api.weixin.qq.com/cityservice/face/identify/getinfo?access_token="; private static final String REQUEST_WECHAT_FACEIMG_URL = "https://api.weixin.qq.com/cityservice/face/identify/getimage?access_token="; /**https://api.weixin.qq.com/cityservice/face/identify/getimage?access_token= * 请求微信服务器返回token信息后获取指定字符串常量 */ private static final String ACCESS_TOKEN_CONST = "access_token"; /** * 用于存放指定appid的accesstoken的有效时间 */ private static final String ACCESS_TOKEN_TIME_CONST = "ACCESS_TOKEN_TIME"; /** * 网页端使用微信js时用到的关键字 */ private static final String JSAPI_TICKET_CONST = "ticket"; /** * js授权有效时间 */ private static final String JSAPI_TICKET_TIME_CONST = "JSAPI_TICKET_TIME"; /** * 发送文本信息 * @param openId 用户openId(关注公众号后的公众平台自动生成的唯一编码) * @param msgContent 消息内容 * @param appId 微信公众号appid * @param secert 微信公众号密钥 * @param accessToken 发消息所需的令牌 * @param openIdList 要发送微信消息的人员openid * @param msgContent 要发送的信息内容 * @return */ public static Map<String, String> sendTextMsg(String appId, String secert, String accessToken, List<String> openIdList, String msgContent){ Map<String, String> resultMap = new HashMap<String, String>(); // String accessToken = getToken(); // if(accessToken == null){ // resultMap.put(SendStatus.GET_ACCESS_TOKEN_FAILD.getCode(), SendStatus.GET_ACCESS_TOKEN_FAILD.getName()); // return resultMap; // } // 组装文本信息 SimplMsg sm = new SimplMsg(MsgTypeEnum.TEXT.getCode()); sm.addData("content", msgContent); for (String openId : openIdList) { String msgBody = toSimplJson(openId, sm); send(accessToken, msgBody); } return null; } /** * 发送多图文消息 * @param appId 微信公众号appid * @param secert 微信公众号密钥 * @param accessToken 发消息所需的令牌 * @param openIdList 要发送微信消息的人员openid * @param msgBody 图文消息封装类 * @return */ public static Map<String, String> sendPicTextMsg(String appId, String secert, String accessToken, List<String> openIdList, PicInfo msgBody){ Map<String, String> resultMap = new HashMap<String, String>(); // String accessToken = getToken(); // if(accessToken == null){ // resultMap.put(SendStatus.GET_ACCESS_TOKEN_FAILD.getCode(), SendStatus.GET_ACCESS_TOKEN_FAILD.getName()); // return resultMap; // } /* 发送多图文消息*/ PicWithTextMsg pics = new PicWithTextMsg(MsgTypeEnum.NEWS.getCode()); List<Map<String, String>> bodyList = new ArrayList<Map<String,String>>(); pics.data = bodyList; Map<String, String> bodyMap = new HashMap<String, String>(); bodyList.add(bodyMap); bodyMap.put("title", msgBody.getTitle()); bodyMap.put("description", msgBody.getDescription()); bodyMap.put("url", msgBody.getUrl()); bodyMap.put("picurl", msgBody.getPicurl()); for (String openId : openIdList) { String msgBodyStr = toImagesJson(openId, pics); send(accessToken, msgBodyStr); } return null; } /** * 获取指定公众号的access_token * @return * @throws Exception */ public static String getAccessToken(String appId, String secert) throws Exception{ System.out.println("开始获取wechat accessToke...."+ "&appid=" + appId + "&secret=" + secert); String req_token_url = REQUEST_TOKEN_URL + "&appid=" + appId + "&secret=" + secert; StringBuilder tokenSbd = null; InputStreamReader isr = null; HttpsURLConnection httpsConn = null; // 先从缓存中去token if(allAccessTokenMap.containsKey(ACCESS_TOKEN_CONST + appId)){ String effectiveTime = (String) allAccessTokenMap.get(ACCESS_TOKEN_TIME_CONST + appId); if(DateUtil.compareDateTime(effectiveTime, util.getFormatDate(new Date(),"YYYY-MM-DD HH:mm:ss"))){ // 有效时间大于当前时间,则access_token有效 return (String) allAccessTokenMap.get(ACCESS_TOKEN_CONST + appId); } } try { URL reqURL = new URL(req_token_url); httpsConn = (HttpsURLConnection) reqURL.openConnection(); isr = new InputStreamReader(httpsConn.getInputStream()); char[] chars = new char[1024]; int len; tokenSbd = new StringBuilder(); while ((len = isr.read(chars)) != -1) { tokenSbd.append(new String(chars, 0, len)); } System.out.println("获取到的tokenSbd:" + tokenSbd.toString()); JSONObject jsonObj = JSONObject.parseObject(tokenSbd.toString()); String accessToken = jsonObj.get(ACCESS_TOKEN_CONST).toString(); // 将当前时间+2小时后的时间存入map中 //allAccessTokenMap.put(ACCESS_TOKEN_TIME_CONST + appId, DateUtil.getAddMinuteDate(new Date(),120)); allAccessTokenMap.put(ACCESS_TOKEN_TIME_CONST + appId, DateUtil.format("YYYY-MM-DD HH:mm:ss", DateUtil.getAddMinuteDate(new Date(),120))); System.out.println("获取到公众号ACCESS_TOKEN:" + accessToken); allAccessTokenMap.put(ACCESS_TOKEN_CONST + appId, accessToken); return accessToken; } catch (IOException e) { e.printStackTrace(); } finally{ if(isr != null){ try { isr.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(httpsConn != null){ httpsConn.disconnect(); } } return null; } /** * 获取指定公众号的JsapiTicket * @return * @throws Exception */ public static String getJsapiTicket(String appId, String secert) throws Exception{ StringBuilder tokenSbd = null; InputStreamReader isr = null; HttpsURLConnection httpsConn = null; // 先从缓存中去token if(allAccessTokenMap.containsKey(JSAPI_TICKET_CONST + appId)){ System.out.println("JSAPI_TICKET_TIME_CONST="+allAccessTokenMap.get(JSAPI_TICKET_TIME_CONST + appId)); String effectiveTime = (String) allAccessTokenMap.get(JSAPI_TICKET_TIME_CONST + appId); if(DateUtil.compareDateTime(effectiveTime, util.getFormatDate(new Date(),"YYYY-MM-DD HH:mm:ss"))){ // 有效时间大于当前时间,则access_token有效 return (String) allAccessTokenMap.get(JSAPI_TICKET_CONST + appId); } } String accessToken = getAccessToken(appId, secert); try { URL reqURL = new URL(REQUEST_JSAPI_TICKET_URL + accessToken); httpsConn = (HttpsURLConnection) reqURL.openConnection(); isr = new InputStreamReader(httpsConn.getInputStream()); char[] chars = new char[1024]; int len; tokenSbd = new StringBuilder(); while ((len = isr.read(chars)) != -1) { tokenSbd.append(new String(chars, 0, len)); } JSONObject jsonObj = JSONObject.parseObject(tokenSbd.toString()); String jsApiTicket = jsonObj.get(JSAPI_TICKET_CONST).toString(); // 将当前时间+2小时后的时间存入map中 allAccessTokenMap.put(JSAPI_TICKET_TIME_CONST + appId, DateUtil.format("YYYY-MM-DD HH:mm:ss", DateUtil.getAddMinuteDate(new Date(),120))); System.out.println("获取到公众号jsApiTicket:" + jsApiTicket); allAccessTokenMap.put(JSAPI_TICKET_CONST + appId, jsApiTicket); return jsApiTicket; } catch (IOException e) { e.printStackTrace(); } finally{ if(isr != null){ try { isr.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(httpsConn != null){ httpsConn.disconnect(); } } return null; } /** * 生成微信权限验证的参数 * @param appId * @param secert * @param url * @return * @throws Exception */ public static Map<String, String> createWXTicket(String appId, String secert, String url) throws Exception { Map<String, String> ret = new HashMap<String, String>(); String nonceStr = util.getUUID(); String timestamp = createTimestamp(); String jsApiTicket = getJsapiTicket(appId, secert); //注意这里参数名必须全部小写,且必须有序 String signature = SignUtil.createSignature(jsApiTicket, nonceStr, timestamp, url); ret.put("url", url); ret.put("jsapi_ticket", jsApiTicket); ret.put("nonceStr", nonceStr); ret.put("timestamp", timestamp); ret.put("signature", signature); ret.put("appid", appId); System.out.println("===========jsapi_ticket:" + jsApiTicket); System.out.println("===========signature:" + signature); System.out.println("===========nonceStr:" + nonceStr); System.out.println("===========timestamp:" + timestamp); System.out.println("===========appid:" + appId); System.out.println("===========url:" + url); return ret; } /** * 拉取微信用户人脸验证信息 * @param code * @return * @throws Exception */ public static Map<String, String> getWxFaceInfo(String appId, String secert, String msgBody) { Map<String, String> resultMap = new HashMap<String, String>(); HttpURLConnection httpURLConnection = null; OutputStream os = null; InputStream in = null; try { //创建URL String accessToken = getAccessToken(appId, secert); URL url = new URL(REQUEST_WECHAT_FACEINFO_URL + accessToken); //由URL的openConnection方法得到一个HttpURLConnection(需要强转) httpURLConnection = (HttpURLConnection) url.openConnection(); //设置post提交 httpURLConnection.setRequestMethod("POST"); //设置超时时间 httpURLConnection.setConnectTimeout(30000); httpURLConnection.setReadTimeout(30000); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); //把请求正文通过OutputStream发出去 os =httpURLConnection.getOutputStream(); os.write(msgBody.getBytes("utf-8")); os.flush(); //判断响应码 200 代表成功 if(httpURLConnection.getResponseCode()==200){ //由HttpURLConnection拿到输入流 in = httpURLConnection.getInputStream(); StringBuffer sb = new StringBuffer(); //根据输入流做一些IO操作 byte [] buff =new byte[1024]; int len=-1; while((len=in.read(buff))!=-1){ sb.append(new String(buff,0,len,"utf-8")); } //System.out.println("微信消息已发送:" + msgBody); //System.out.println("微信平台回执:" + sb.toString()); /*JSONObject jsonObj = JSONObject.parseObject(sb.toString());*/ resultMap.put("obj", sb.toString()); }else{ resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); } return resultMap; }catch (Exception e){ e.printStackTrace(); }finally{ try { if(os != null){ os.close(); } if(in != null){ in.close(); } } catch (IOException e) { e.printStackTrace(); } if(httpURLConnection != null){ httpURLConnection.disconnect(); } } resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); return resultMap; } /** * 拉取微信用户人脸验证照片 * @param code * @return * @throws Exception */ public static Map<String, String> getWxFaceImg(String appId, String secert, String msgBody) { Map<String, String> resultMap = new HashMap<String, String>(); HttpURLConnection httpURLConnection = null; OutputStream os = null; InputStream in = null; try { //创建URL String accessToken = getAccessToken(appId, secert); URL url = new URL(REQUEST_WECHAT_FACEIMG_URL + accessToken); //由URL的openConnection方法得到一个HttpURLConnection(需要强转) httpURLConnection = (HttpURLConnection) url.openConnection(); //设置post提交 httpURLConnection.setRequestMethod("POST"); //设置超时时间 httpURLConnection.setConnectTimeout(30000); httpURLConnection.setReadTimeout(30000); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); //把请求正文通过OutputStream发出去 os =httpURLConnection.getOutputStream(); os.write(msgBody.getBytes("utf-8")); os.flush(); //判断响应码 200 代表成功 if(httpURLConnection.getResponseCode()==200){ //由HttpURLConnection拿到输入流 in = httpURLConnection.getInputStream(); byte[] data = readInputStream(in); //new一个文件对象用来保存图片,默认保存当前工程根目录 String path = ServletActionContext.getServletContext().getRealPath(Constants.IMGPATH); File dir = new File(path); String fileFileName=new Date().getTime()+".jpg"; System.out.println("fileFileName="+fileFileName); File imageFile = new File(dir,fileFileName); //创建输出流 FileOutputStream outStream = new FileOutputStream(imageFile); //写入数据 outStream.write(data); //关闭输出流 outStream.close(); resultMap.put("fileFileName", fileFileName); }else{ resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); } return resultMap; }catch (Exception e){ e.printStackTrace(); }finally{ try { if(os != null){ os.close(); } if(in != null){ in.close(); } } catch (IOException e) { e.printStackTrace(); } if(httpURLConnection != null){ httpURLConnection.disconnect(); } } resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); return resultMap; } public static byte[] readInputStream(InputStream inStream) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); //创建一个Buffer字符串 byte[] buffer = new byte[1024]; //每次读取的字符串长度,如果为-1,代表全部读取完毕 int len = 0; //使用一个输入流从buffer里把数据读取出来 while( (len=inStream.read(buffer)) != -1 ){ //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 outStream.write(buffer, 0, len); } //关闭输入流 inStream.close(); //把outStream里的数据写入内存 return outStream.toByteArray(); } /** * 生成时间戳 * @return */ private static String createTimestamp() { return Long.toString(System.currentTimeMillis() / 1000); } /** * 创建菜单 * @param accessToken * @param menuJson * @throws Exception */ public static void createWechatMenu(String accessToken, String menuJson) throws Exception{ System.out.println("开始创建微信菜单>>>"); URL url = null; try { url = new URL(MENU_CREATE_URL + accessToken); } catch (MalformedURLException e) { throw new Exception("URL初始化失败!", e); } HttpURLConnection http = (HttpURLConnection) url.openConnection(); http.setRequestMethod("POST"); http.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); http.setDoOutput(true); http.setDoInput(true); System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//连接超时30秒 System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //读取超时30秒 http.connect(); OutputStream os= http.getOutputStream(); os.write(menuJson.getBytes("UTF-8"));//传入参数 os.flush(); os.close(); System.out.println("完成创建微信菜单>>>"); } /** * 拉取微信用户信息 * @param code * @return * @throws Exception */ public static JSONObject getWechatUserInfo(String appId, String secert, String openId) throws Exception{ StringBuilder rstSbd = null; InputStreamReader isr = null; HttpsURLConnection httpsConn = null; String accessToken = getAccessToken(appId, secert); System.out.println("++++++++++++开始获取微信头像信息..."); String reqUserInfoUrl = REQUEST_WECHAT_USERINFO_URL + "&access_token=" + accessToken + "&openid=" + openId; try { URL reqURL = new URL(reqUserInfoUrl); httpsConn = (HttpsURLConnection) reqURL.openConnection(); isr = new InputStreamReader(httpsConn.getInputStream(),"UTF-8"); char[] chars = new char[1024]; int len; rstSbd = new StringBuilder(); while ((len = isr.read(chars)) != -1) { rstSbd.append(new String(chars, 0, len)); } //String jsonZhcnStr = new String(rstSbd.toString().getBytes("ISO-8859-1"), "UTF-8"); JSONObject jsonObj = JSONObject.parseObject(rstSbd.toString()); //String nickName = jsonObj.get("nickname") == null ? "" : jsonObj.get("nickname").toString(); //String headImgUrl = jsonObj.get("headimgurl") == null ? "" : jsonObj.get("headimgurl").toString(); return jsonObj; } catch (IOException e) { e.printStackTrace(); } finally{ if(isr != null){ try { isr.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(httpsConn != null){ httpsConn.disconnect(); } } return null; } /** * 根据微信授权码获取openId等信息 * @param code * @return */ public static String getAccessTokenByCode(String appId, String secert, String code){ String req_token_url = REQUEST_ACCESS_TOKEN_URL + "&appid=" + appId + "&secret=" + secert + "&code=" + code; StringBuilder tokenSbd = null; InputStreamReader isr = null; HttpsURLConnection httpsConn = null; System.out.println("开始根据code获取accessToken...发送http请求。"+ "&appid=" + appId + "&secret=" + secert + "&code=" + code); try { URL reqURL = new URL(req_token_url); httpsConn = (HttpsURLConnection) reqURL.openConnection(); isr = new InputStreamReader(httpsConn.getInputStream()); char[] chars = new char[1024]; int len; tokenSbd = new StringBuilder(); while ((len = isr.read(chars)) != -1) { tokenSbd.append(new String(chars, 0, len)); } //System.out.println("获取到的数据信息:" + tokenSbd.toString()); JSONObject jsonObj = JSONObject.parseObject(tokenSbd.toString()); //System.out.println(jsonObj.toJSONString()); System.out.println("获取openId:" + jsonObj.get("openid")); String openId = jsonObj.get("openid") == null ? "" : jsonObj.get("openid").toString(); System.out.println(">>>根据code["+ code +"]获取openID["+ openId +"]"); return openId; } catch (IOException e) { e.printStackTrace(); } finally{ if(isr != null){ try { isr.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(httpsConn != null){ httpsConn.disconnect(); } } return null; } /** * send发送订阅通知 * @param appId * @param secert * @param templateData 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } } * @return */ private static Map<String, String> sendSubscribeBizsend(String appId, String secert, JSONObject templateData){ Map<String, String> resultMap = new HashMap<String, String>(); HttpURLConnection httpURLConnection = null; OutputStream os = null; InputStream in = null; try { String accessToken = WechatUtil.getAccessToken(appId, secert); //创建URL URL url = new URL(SEND_MSG_SUBSCRIBE_BIZSEND_URL + accessToken); //由URL的openConnection方法得到一个HttpURLConnection(需要强转) httpURLConnection = (HttpURLConnection) url.openConnection(); //设置post提交 httpURLConnection.setRequestMethod("POST"); //设置超时时间 httpURLConnection.setConnectTimeout(30000); httpURLConnection.setReadTimeout(30000); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); //把请求正文通过OutputStream发出去 os =httpURLConnection.getOutputStream(); os.write(templateData.toJSONString().getBytes("utf-8")); os.flush(); //判断响应码 200 代表成功 if(httpURLConnection.getResponseCode()==200){ //由HttpURLConnection拿到输入流 in = httpURLConnection.getInputStream(); StringBuffer sb = new StringBuffer(); //根据输入流做一些IO操作 byte [] buff =new byte[1024]; int len=-1; while((len=in.read(buff))!=-1){ sb.append(new String(buff,0,len,"utf-8")); } System.out.println("微信消息已发送:"); System.out.println("微信平台回执:" + sb.toString()); resultMap.put(SendStatus.SUCCESS.getCode(), SendStatus.SUCCESS.getName()); }else{ resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); } return resultMap; }catch (Exception e){ e.printStackTrace(); }finally{ try { if(os != null){ os.close(); } if(in != null){ in.close(); } } catch (IOException e) { e.printStackTrace(); } if(httpURLConnection != null){ httpURLConnection.disconnect(); } } resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); return resultMap; } /** * 发起http请求 * @param accessToken * @param msgBody * @return */ private static Map<String, String> send(String accessToken, String msgBody){ Map<String, String> resultMap = new HashMap<String, String>(); HttpURLConnection httpURLConnection = null; OutputStream os = null; InputStream in = null; try { //创建URL URL url = new URL(SEND_MSG_URL + accessToken); //由URL的openConnection方法得到一个HttpURLConnection(需要强转) httpURLConnection = (HttpURLConnection) url.openConnection(); //设置post提交 httpURLConnection.setRequestMethod("POST"); //设置超时时间 httpURLConnection.setConnectTimeout(30000); httpURLConnection.setReadTimeout(30000); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); //把请求正文通过OutputStream发出去 os =httpURLConnection.getOutputStream(); os.write(msgBody.getBytes("utf-8")); os.flush(); //判断响应码 200 代表成功 if(httpURLConnection.getResponseCode()==200){ //由HttpURLConnection拿到输入流 in = httpURLConnection.getInputStream(); StringBuffer sb = new StringBuffer(); //根据输入流做一些IO操作 byte [] buff =new byte[1024]; int len=-1; while((len=in.read(buff))!=-1){ sb.append(new String(buff,0,len,"utf-8")); } System.out.println("微信消息已发送:" + msgBody); System.out.println("微信平台回执:" + sb.toString()); resultMap.put(SendStatus.SUCCESS.getCode(), SendStatus.SUCCESS.getName()); }else{ resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); } return resultMap; }catch (Exception e){ e.printStackTrace(); }finally{ try { if(os != null){ os.close(); } if(in != null){ in.close(); } } catch (IOException e) { e.printStackTrace(); } if(httpURLConnection != null){ httpURLConnection.disconnect(); } } resultMap.put(SendStatus.HTTP_CONNECT_FAILD.getCode(), SendStatus.HTTP_CONNECT_FAILD.getName()); return resultMap; } /** * 普通消息实体转换为json对象工具类 * @param openid * @param msg * @return */ private static String toSimplJson(String openId, SimplMsg msgContext) { JSONObject json = new JSONObject(); json.put("touser", openId); json.put("msgtype", msgContext.getMsgtype()); json.put(msgContext.getMsgtype(), msgContext.getData()); return json.toString(); } /** * 多图文消息转换为json对象工具类 * @param openId * @param msg * @return */ private static String toImagesJson(String openId, PicWithTextMsg msg){ JSONObject j = new JSONObject(); j.put("articles", msg.getData()); JSONObject json = new JSONObject(); json.put("touser", openId); json.put("msgtype", msg.getMsgType()); json.put(msg.getMsgType(), j); return json.toString(); } /** * 发送消息类型枚举类 * @author wjy * */ public enum MsgTypeEnum{ TEXT("text", "文本消息"), NEWS("news", "图文消息"); private String code; private String name; MsgTypeEnum(String code, String name){ this.code = code; this.name = name; } public String getCode() { return code; } public String getName() { return name; } public void setCode(String code) { this.code = code; } public void setName(String name) { this.name = name; } }; /** * 发送消息状态枚举内部类 * @author wjy * */ public enum SendStatus{ SUCCESS("1", "成功"), GET_ACCESS_TOKEN_FAILD("2", "获取token信息失败"), HTTP_CONNECT_FAILD("3", "http链接失败"), UNKNOW_ERROR("-1", "未知错误"); private String code; private String name; SendStatus(String code, String name){ this.code = code; this.name = name; } public String getCode() { return code; } public String getName() { return name; } public void setCode(String code) { this.code = code; } public void setName(String name) { this.name = name; } }; /** * 简单消息内部类 * @author wjy * */ static class SimplMsg{ /** * 发送消息类型 */ private String msgtype; private Map<String,String> data = new HashMap<String,String>(); public Map<String,String> getData(){ return data; } public String getMsgtype() { return msgtype; } /** * 实例化指定类型的消息 * */ public SimplMsg(String msgtype){ this.msgtype = msgtype; } /** * 添加消息内容 */ public SimplMsg addData(String key,String value){ data.put(key, value); return this; } } /** * 图文消息内部封装类 * @author wjy * */ static class PicWithTextMsg{ private String msgType; private List<Map<String,String>> data = new ArrayList<Map<String,String>>(); public List<Map<String,String>> getData(){ return data; } public String getMsgType() { return msgType; } /** * 实例化指定类型的消息 * */ public PicWithTextMsg(String msgType){ this.msgType = msgType; } /** * 添加消息内容 */ public PicWithTextMsg addData(Map<String,String> map){ data.add(map); return this; } } /** * 图文信息实体类 * @author wjy * */ public static class PicInfo{ private String title; private String description; private String url; private String picurl; public String getTitle() { return title; } public String getDescription() { return description; } public String getUrl() { return url; } public String getPicurl() { return picurl; } public void setTitle(String title) { this.title = title; } public void setDescription(String description) { this.description = description; } /** * 外链url(即点击图文时的链接) * @param url */ public void setUrl(String url) { this.url = url; } /** * 要展示的图片的url * @param picurl */ public void setPicurl(String picurl) { this.picurl = picurl; } } // **************************************************************** /* public void doSend() { List<CdptsArticle> toSendNewsList = new ArrayList<>(); // 1.获取新闻列表 toSendNewsList = getArticleListFromCdpts(); // 再去获取一次,有时候第一次获取不到,不知道为什么 if (toSendNewsList.size() == 0) { toSendNewsList = getArticleListFromCdpts(); } // 2.移除已发送的新闻 toSendNewsList = removeAlreadySentArticle(toSendNewsList); if (toSendNewsList.size() == 0) { //logger.info("----------没有文章需要群发----------"); return; } // 最多群发8条消息 if (toSendNewsList.size() > 8) { toSendNewsList = toSendNewsList.subList(0, 8); } //logger.info("----------群发的消息----------"); for (CdptsArticle article : toSendNewsList) { logger.info("----------{}----------", article.getTitle()); } // 3.上传并设置封面图片 toSendNewsList = setCoverImage(toSendNewsList); // 4.群发图文消息json封装 String groupSendMessageJsonStr = getGroupSendMessageJsonStr(toSendNewsList); // 5.上传群发图文消息 String mediaId = uploadGroupSendMessage(groupSendMessageJsonStr); // 5.群发 if (StringUtils.isNotEmpty(mediaId)) { String mode = prop.get("active"); if (StringUtils.isNotBlank(mode) && mode.equals("dev")) { logger.info("测试环境,预览"); String openId = "你的测试openid"; sendToPreview(toSendNewsList, openId, mediaId); } else { logger.info("正式环境,群发"); sendToAll(toSendNewsList, mediaId); } } } */ /** * 设置图文消息的封面图片 * * @param newsList * @return */ /* private List<CdptsArticle> setCoverImage(List<CdptsArticle> newsList) { String accessToken = accessTokenUtil.getAccessToken(); // 3.将待发送的新闻填充 List<CdptsArticle> detialArticleList = new ArrayList<>(); // 4.封装新闻详情,并得到新闻列表 for (CdptsArticle article : newsList) { CdptsArticle articleWithDetial = getArticleDetialAndReplaceImage(article.getUrl()); try { // 下载封面图片到本地 String localImage = imageService.saveImageToDisk(articleWithDetial.getImageUrl(), imageSavePath); ImageUtil.thumbImage(localImage); // 上传封面到微信 String jsonStr = HttpUtil.sendPost(postImageMediaUrl.replace("ACCESS_TOKEN", accessToken), new File(localImage)); logger.info("----------上传封面图片返回结果:{}----------" + jsonStr); try { JSONObject object = new JSONObject(jsonStr); logger.info("----------得到的封面图片media_id:{}----------", object.get("media_id")); articleWithDetial.setImageMediaId((String) object.get("media_id")); } catch (Exception e) { logger.error("----------上传封面发生错误:{}", e.getMessage()); } } catch (Exception e) { logger.error("----------下载封面,上传封面到微信过程发生错误:{}", e.getMessage()); } detialArticleList.add(articleWithDetial); } logger.info("----------最终群发图文列表:{}----------", detialArticleList); return detialArticleList; } private String getGroupSendMessageJsonStr(List<CdptsArticle> toSendNewsList) { List<GroupSendMessage> groupSendMessageList = new ArrayList<>(); for (CdptsArticle cdptsArticle : toSendNewsList) { GroupSendMessage groupSendMessage = new GroupSendMessage(); groupSendMessage.setThumb_media_id(cdptsArticle.getImageMediaId()); groupSendMessage.setAuthor(cdptsArticle.getAuthor()); groupSendMessage.setTitle(cdptsArticle.getTitle()); groupSendMessage.setContent_source_url(cdptsArticle.getUrl()); groupSendMessage.setContent(cdptsArticle.getContent()); groupSendMessage.setShow_cover_pic(0); groupSendMessageList.add(groupSendMessage); } logger.info("----------最终封装的图文消息列表:{}----------", groupSendMessageList); Map<String, Object> jsonMap = new HashMap<>(); jsonMap.put("articles", groupSendMessageList); String groupSendMessageJsonStr = gson.toJson(jsonMap); logger.info("----------最终要发送的图文消息json数据:{}----------", groupSendMessageJsonStr); return groupSendMessageJsonStr; } private String uploadGroupSendMessage(String groupSendMessageJsonStr) { String accessToken = accessTokenUtil.getAccessToken(); String postNewsResult = HttpUtil.sendPost(postNewsUrl.replace("ACCESS_TOKEN", accessToken), groupSendMessageJsonStr); logger.info("----------上传群发图文消息的返回结果:{}----------", postNewsResult); String mediaId = ""; try { JSONObject object = new JSONObject(postNewsResult); mediaId = (String) object.get("media_id"); } catch (JSONException e) { logger.error("上传群发图文消息发生错误{}", postNewsResult); } return mediaId; } public void sendToPreview(List<CdptsArticle> toSendNewsList, String openId, String mediaId) { String accessToken = accessTokenUtil.getAccessToken(); SendToOpenIdPreview sendToPreview = new SendToOpenIdPreview(openId, mediaId); String sendToPreviewJsonStr = gson.toJson(sendToPreview); logger.info("----------预览的的json:{}----------", sendToPreviewJsonStr); String sentToPreviewResult = HttpUtil.sendPost(sendToPreviewUrl.replace("ACCESS_TOKEN", accessToken), sendToPreviewJsonStr); logger.info("----------预览发送结果:{}----------", sentToPreviewResult); checkSendResult(toSendNewsList, sentToPreviewResult); } */ /** * 根据openid 获取Unionid * * @param token * @param openid * @return */ public static String getUnionid(String token, String openid) { System.out.println(token+"----------"+openid); String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + token + "&openid=" + openid + "&lang=zh_CN"; RestTemplate restTemplate = new RestTemplate(); String result = restTemplate.getForObject(url, String.class); if (StringUtils.isNotBlank(result)) { return JSONObject.parseObject(result).getString("unionid"); } return null; } /** * 服务类目为:“IT科技 > 软件服务提供商 > 服务完成通知”的模板数据结构 * @param toUserOpenId * @param templateId * @param serviceItem * @param submitUser * @return */ public static JSONObject dataJsonObjectForITSoftwareServiceSuccess(String toUserOpenId, String serviceItem, String submitUser, String page, String miniProgram) { JSONObject jsonData = new JSONObject(); jsonData.put("touser", toUserOpenId); jsonData.put("template_id", SERVICE_CATEGORY_IT_SOFTWARE_SERVICE_SUCCESS); JSONObject paramData = new JSONObject(); JSONObject paramData1 = new JSONObject(); paramData1.put("value", serviceItem); paramData.put("thing1", paramData1); JSONObject paramData2 = new JSONObject(); paramData2.put("value", submitUser); paramData.put("thing18", paramData2); jsonData.put("data", paramData); return jsonData; } public static void sendWechatMessage(String appId, // 微信公众号appId String secret, // 微信公众号秘钥 String templateId, // 微信公众号消息模板ID String openId, // 微信公众号openId String url, // 微信公众号消息跳转链接 String first, // 微信公众号消息模板first字段 String keyword1, // 微信公众号消息模板keyword1字段 String keyword2, // 微信公众号消息模板keyword2字段 String keyword3, // 微信公众号消息模板keyword3字段 String keyword4, // 微信公众号消息模板keyword4字段 String remark // 微信公众号消息模板remark字段 ) { WxMpInMemoryConfigStorage wxStorage = new WxMpInMemoryConfigStorage(); wxStorage.setAppId(appId); wxStorage.setSecret(secret); WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(wxStorage); // 2.模板配置信息赋值 WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder().toUser(openId).templateId(templateId) .url(url).build(); // 模板内容添加 Util util = Util.getInstance(); if (!util.isEmpty(first)) templateMessage.addData(new WxMpTemplateData("first", first, "#FF00FF")); if (!util.isEmpty(keyword1)) templateMessage.addData(new WxMpTemplateData("keyword1", keyword1, "#000000")); if (!util.isEmpty(keyword2)) templateMessage.addData(new WxMpTemplateData("keyword2", keyword2, "#000000")); if (!util.isEmpty(keyword3)) templateMessage.addData(new WxMpTemplateData("keyword3", keyword3, "#000000")); if (!util.isEmpty(keyword4)) templateMessage.addData(new WxMpTemplateData("keyword4", keyword4, "#000000")); if (!util.isEmpty(remark)) templateMessage.addData(new WxMpTemplateData("remark", remark, "#000000")); try { // 模板消息发送 wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage); } catch (Exception e) { System.out.println("推送失败:" + e.getMessage()); e.printStackTrace(); } } public static void main(String[] args) { String toOpenId = "odjhD5gAPivi73RMWnzsSCgLrRyg"; String serviceItem = "高龄验证成功"; String submitUser = "民政局"; JSONObject templateData = dataJsonObjectForITSoftwareServiceSuccess(toOpenId, serviceItem, submitUser, "", ""); sendSubscribeBizsend(Constants.WECHAT_APPID_BMTG, Constants.WECHAT_SECERT_BMTG, templateData); } }