网页授权获取用户基本信息---获取code码

今天碰到微信公众号实现菜单跳转请求用户参数

获取code码碰到了这个问题

网页微信第三方登录-redirect_uri参数错误

通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

目录

1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

5 附:检验授权凭证(access_token)是否有效

第一步:用户同意授权,获取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码然后请求
  如果跳转的请求是action或者别的(控制层)方法参数不能加载方法体中接收参数值就可以

用户同意授权后

如果用户同意授权,页面将跳转至 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);
    }
}

 

posted @ 2020-04-11 10:55  Ferocious  阅读(1325)  评论(0编辑  收藏  举报