微信开发推送消息图片_微信公众号开发 服务器向微信公众号 推送图片 教程csdn - CSDN
  • 上篇文章介绍了开启回调模式,开始回调模式后我们就要实现聊天功能了。平时使用微信聊天可以发送文本消息、语音、... 2、企业号把用户发送的消息或用户触发的事件推送给企业应用,由企业应用处理,以下称回调模式。

            上篇文章介绍了开启回调模式,开始回调模式后我们就要实现聊天功能了。平时使用微信聊天可以发送文本消息、语音、图片、视频等,这里只实现了其中的一些功能和大家分享。

    一、与微信企业号建立连接

     1、企业应用调用企业号提供的接口,管理或查询企业号后台所管理的资源、或给成员发送消息等,以下称主动调用模式

     2、企业号把用户发送的消息或用户触发的事件推送给企业应用,由企业应用处理,以下称回调模式

     3、用户在微信中阅读企业应用下发的H5页面,该页面可以调用微信提供的原生接口,使用微信开放的终端能力,以下称JSAPI模式

              这是微信企业号的开发文档中写的,但是我们一般使用前两种方式。

              其实主动调用和回调都是相对的,这是站在微信服务器的角度,微信服务器通过企业号给微信客户端发送消息是主动调用,微信客户端主动发送消息去调用微信服务器相对服务器来说就是被动调用(回调)。


    二、主被动调用微信服务器处理的数据格式

    1.主调:服务器向微信客户端发送json格式的数据,数据不需要加密

    2.回调:微信客户端发送的消息需要AES加密,服务器接受的消息是xml格式

         这两条用一张图表示如下:

        

    三、聊天原理图

              首先微信客户端发送消息到服务器处理,数据以xml格式传输到第三方服务器后,第三方服务器再将数据转为json格式,传送给微信服务器,发送给客户端。

    三、代码实现

        有了上面的原理基础,下面是代码部分

    1.servlet

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		request.setCharacterEncoding("UTF-8");
    		response.setCharacterEncoding("UTF-8"); 
    		
            String msg_signature = request.getParameter("msg_signature");  
           
            String timestamp = request.getParameter("timestamp");  
            
            String nonce = request.getParameter("nonce"); 
          
            InputStream inputStream = request.getInputStream();  
            String postData = IOUtils.toString(inputStream, "UTF-8");  
            System.out.println(postData);  
            
            String msg = "";  
            WXBizMsgCrypt wxcpt = null;  
            try {  
                wxcpt = new WXBizMsgCrypt(sToken , sEncodingAESKey , sCorpID );  
                msg = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);  
            } catch (AesException e) {  
                e.printStackTrace();   
            }  
            System.out.println("msg=" + msg);  
                
            //获取接口访问凭证
            String accessToken = CommonUtil.getToken("wxe510946434680dab", "eWTaho766INvp4e1MCsz1mHYuT2DAleb62REQ3vsFizhY4vtmwZpKweuxUVh33G0").getAccessToken();
            try {
    		@SuppressWarnings("unused")
    		boolean flag = ChatService1.sendMessage(accessToken,msg);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    }  

    2.service

    public class ChatService1 {
    
    	public static boolean sendMessage(String accessToken,String msg) throws Exception{
    		boolean flag =  false;
    		Map<String, String> requestMap = MessageUtil.parseXml(msg);	
    		// 发送者
    		String fromUserName = requestMap.get("FromUserName");
    		// 消息类型
    		String msgType = requestMap.get("MsgType");
    	
    		if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)){//如果是文本客服消息
    			String Content = requestMap.get("Content");//文本消息的消息内容
    			//组装文本客服消息,参数1:用户id;参数2:发送的内容
    			jsonMsg = AdvancedUtil.makeTextCustomMessage("lishehe|zhisheng|zhangwenyuan|lixinjiang", Content);
    		}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)){//发送的是图片
    			String mediaId = requestMap.get("MediaId");
    			jsonMsg = AdvancedUtil.makeImageCustomMessage("lishehe|zhisheng|zhangwenyuan|lixinjiang", mediaId);
    		}else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){
    			String mediaId = requestMap.get("MediaId");
    			jsonMsg= AdvancedUtil.makeVoiceCustomMessage("lishehe|zhisheng|zhangwenyuan|lixinjiang", mediaId);
    		}
    		flag = AdvancedUtil.sendCustomMessage(accessToken, jsonMsg);
    		return flag;
    	}
    }

    3.工具类

    public class AdvancedUtil {
    	private static Logger log = LoggerFactory.getLogger(AdvancedUtil.class);
    
    	/**
    	 * 组装发送文本消息
    	 * @return
    	 */
    	public static String makeTextCustomMessage(String openId, String content) {
    		content = content.replace("\"", "\\\"");
    		String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"text\",\"agentid\":\"%s\",\"text\":{\"content\":\"%s\"}}";
    		return String.format(jsonMsg, openId, 14,content);
    	}
    
    	/**
    	 * 组装发送图片消息
    	 * 
    	 * @return
    	 */
    	public static String makeImageCustomMessage(String openId, String mediaId) {
    		String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"image\",\"agentid\":\"%s\",\"image\":{\"media_id\":\"%s\"}}";
    		return String.format(jsonMsg, openId,14, mediaId);
    	}
    
    	/**
    	 * 组装发送语音消息
    	 * 
    	 * @return
    	 */
    	public static String makeVoiceCustomMessage(String openId, String mediaId) {
    		String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"voice\",\"agentid\":\"%s\",\"voice\":{\"media_id\":\"%s\"}}";
    		return String.format(jsonMsg, openId,14, mediaId);
    	}

    四、总结

             这样就实现了消息的接收和推送,第三方服务器将接受的xml数据先解密解析,从中获取消息类型,然后将要发送的消息封装后转为json格式,并传送给微信服务器在发送到客户端。

    展开全文
  • 在软件程序实际应用中,在软件中推送可能还不能满足实际需求,需要把消息推送到用户手机,目前比较好的方式,可能是微信消息推送。因此做一个记录 企业微信/企业号注册 微信消息推送需要配合 企业微信号 做消息推送 ...


    在软件程序实际应用中,在软件中推送可能还不能满足实际需求,需要把消息推送到用户手机,目前比较好的方式,可能是微信消息推送。因此做一个记录

    企业微信/企业号注册

    微信消息推送需要配合 企业微信号 做消息推送
    在这里插入图片描述
    注册连接

    也可以使用微信公众号实现消息推送。

    微信认证

    不管什么方式都需要企业认证,认证方式如下:
    需要支付300每次的认证费用
    公众号企业认证流程

    消息推送

    服务号

    1. text消息
    2. image消息
    3. voice消息
    4. video消息
    5. file消息
    6. news消息
    7. mpnews消息

    text消息

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "text",
       "agentid": 1,
       "text": {
           "content": "Holiday Request For Pony(http://xxxxx)"
       },
       "safe":0
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:text (支持消息型应用跟主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    content 是 消息内容,最长不超过2048个字节,注意:主页型应用推送的文本消息在微信端最多只显示20个字(包含中英文)
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    image消息

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "image",
       "agentid": 1,
       "image": {
           "media_id": "MEDIA_ID"
       },
       "safe":0
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:image(不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    media_id 是 图片媒体文件id,可以调用上传临时素材或者永久素材接口获取,永久素材media_id必须由发消息的应用创建
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    voice消息

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "voice",
       "agentid": 1,
       "voice": {
           "media_id": "MEDIA_ID"
       },
       "safe":0
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:voice (不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    media_id 是 语音文件id,可以调用上传临时素材或者永久素材接口获取
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    video消息

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "video",
       "agentid": 1,
       "video": {
           "media_id": "MEDIA_ID",
           "title": "Title",
           "description": "Description"
       },
       "safe":0
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:video (不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    media_id 是 视频媒体文件id,可以调用上传临时素材或者永久素材接口获取
    title 否 视频消息的标题,不超过128个字节,超过会自动截断
    description 否 视频消息的描述,不超过512个字节,超过会自动截断
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    file消息

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "file",
       "agentid": 1,
       "file": {
           "media_id": "MEDIA_ID"
       },
       "safe":"0"
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:file (不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    media_id 是 媒体文件id,可以调用上传临时素材或者永久素材接口获取
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    news消息

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "news",
       "agentid": 1,
       "news": {
           "articles":[
               {
                   "title": "Title",
                   "description": "Description",
                   "url": "URL",
                   "picurl": "PIC_URL"
               },
               {
                   "title": "Title",
                   "description": "Description",
                   "url": "URL",
                   "picurl": "PIC_URL"
               }    
           ]
       }
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:news (不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    articles 是 图文消息,一个图文消息支持1到8条图文
    title 否 标题,不超过128个字节,超过会自动截断
    description 否 描述,不超过512个字节,超过会自动截断
    url 否 点击后跳转的链接。
    picurl 否 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640320,小图8080。如不填,在客户端不显示图片

    mpnews消息

    注:mpnews消息与news消息类似,不同的是图文消息内容存储在微信后台,并且支持保密选项。每个应用每天最多可以发送100次。

    a)发送时直接带上mpnews内容:

    {
       "touser": "UserID1|UserID2|UserID3",
       "toparty": " PartyID1 | PartyID2 ",
       "totag": " TagID1 | TagID2 ",
       "msgtype": "mpnews",
       "agentid": 1,
       "mpnews": {
           "articles":[
               {
                   "title": "Title",
                   "thumb_media_id": "id",
                   "author": "Author",
                   "content_source_url": "URL",
                   "content": "Content",
                   "digest": "Digest description",
                   "show_cover_pic": "0"
               },
               {
                   "title": "Title",
                   "thumb_media_id": "id",
                   "author": "Author",
                   "content_source_url": "URL",
                   "content": "Content",
                   "digest": "Digest description",
                   "show_cover_pic": "0"
               }
           ]
       },
       "safe":0
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:mpnews (不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    articles 是 图文消息,一个图文消息支持1到8个图文
    title 是 图文消息的标题,不超过128个字节,超过会自动截断
    thumb_media_id 是 图文消息缩略图的media_id, 可以在上传多媒体文件接口中获得。此处thumb_media_id即上传接口返回的media_id
    author 否 图文消息的作者,不超过64个字节
    content_source_url 否 图文消息点击“阅读原文”之后的页面链接
    content 是 图文消息的内容,支持html标签,不超过666 K个字节
    digest 否 图文消息的描述,不超过512个字节,超过会自动截断
    show_cover_pic 否 是否显示封面,1为显示,0为不显示
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    b)发送时使用永久图文素材ID:

    {
       "touser": "UserI1|UserID2|UserID3", 
       "toparty": " PartyID1 | PartyID2 ", 
       "msgtype": "mpnews", 
       "agentid": 1, 
       "mpnews": {
           "media_id": "MEDIA_ID"
       }, 
       "safe": 0
    }
    

    参数 必须 说明
    touser 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
    toparty 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    totag 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    msgtype 是 消息类型,此时固定为:mpnews (不支持主页型应用)
    agentid 是 企业应用的id,整型。可在应用的设置页面查看
    media_id 是 素材资源标识ID,通过上传永久图文素材接口获得。注:必须是在该agent下创建的。
    safe 否 表示是否是保密消息,0表示否,1表示是,默认0

    企业微信数据接口

    消息类型
    文本消息
    图片消息
    语音消息
    视频消息
    文件消息
    文本卡片消息
    图文消息
    图文消息(mpnews)

    应用支持推送文本、图片、视频、文件、图文等类型。

    请求方式:POST(HTTPS)
    请求地址: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN

    参数说明:

    参数 是否必须 说明
    access_token 是 调用接口凭证
    各个消息类型的具体POST格式请阅后续“消息类型”部分。
    如果有在管理端对应用设置“在微工作台中始终进入主页”,应用在微信端只能接收到文本消息,并且文本消息的长度限制为20字节,超过20字节会被截断。同时其他消息类型也会转换为文本消息,提示用户到企业微信查看。
    支持id转译,将userid/部门id转成对应的用户名/部门名,目前仅文本/文本卡片/图文/图文(mpnews)这四种消息类型的部分字段支持。具体支持的范围和语法,请查看附录id转译说明。
    支持重复消息检查,当指定 “enable_duplicate_check”: 1开启: 表示在一定时间间隔内,同样内容(请求json)的消息,不会重复收到;时间间隔可通过duplicate_check_interval指定,默认1800秒。
    返回示例:

     {
       "errcode" : 0,
       "errmsg" : "ok",
       "invaliduser" : "userid1|userid2", // 不区分大小写,返回的列表都统一转为小写
       "invalidparty" : "partyid1|partyid2",
       "invalidtag": "tagid1|tagid2"
     }
    

    如果部分接收人无权限或不存在,发送仍然执行,但会返回无效的部分(即invaliduser或invalidparty或invalidtag),常见的原因是接收人不在应用的可见范围内。
    如果全部接收人无权限或不存在,则本次调用返回失败,errcode为81013。

    后台开发

    选择第三方推送工具或者自己开发消息推送后台

    开发实现案例
    1、微信企业号下的消息推送
    2、微信企业号开发:主动发送消息

    展开全文
  • 业务大致逻辑: 1.授权获取code 2.通过code获取openid ...4.公众号推送图片到用户 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {...
    业务大致逻辑:
    1.授权获取code
    2.通过code获取openid
    3.上传图片到微信服务器获取mediaId
    4.公众号推送图片到用户
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
       String backUri = "";
       String state = orid;
       backUri = URLEncoder.encode(backUri);
       String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"
             + "appid="+ appid+ "&redirect_uri="+"xx.jsp"+ "&response_type=code&scope=snsapi_base&state="+state+"#wechat_redirect"+"&connect_redirect=1";
       resp.sendRedirect(url);
    }
    .action
    
    
    String code=request.getParameter("code");
    String filepath=WebContant.REALPATH+"/example/people.jpg";
       String access_token = WX_TokenUtil.getWXToken().getAccessToken();
        String openid= (String) getRequest().getSession().getAttribute("openid");
       if(openid==null||"".equals(openid)) {  //微信授权时会运行两次,第二次的openid为null(暂不知原因)  
          openid = WxSendPicUtil.getOpenId(code);
          getRequest().getSession().setAttribute("openid",openid);
       }
       String mediaId = WxSendPicUtil.upload(filepath, access_token, "image");
          WxSendPicUtil.sendPicOrVoiceMessageToUser(mediaId, openid, "image", access_token);
    AccessToken 实体类
    public class AccessToken implements Serializable {
        //获取到的凭证
        private String accessToken;
        //凭证有效时间,单位:秒
        private int expiresin;
        /**
         * @return the accessToken
         */
        public String getAccessToken() {
            return accessToken;
        }
        /**
         * @param accessToken the accessToken to set
         */
        public void setAccessToken(String accessToken) {
            this.accessToken = accessToken;
        }
        /**
         * @return the expiresin
         */
        public int getExpiresin() {
            return expiresin;
        }
        /**
         * @param expiresin the expiresin to set
         */
        public void setExpiresin(int expiresin) {
            this.expiresin = expiresin;
        }
        public AccessToken() {
            // TODO Auto-generated constructor stub
        }
    
    }
    WxSendPicUtil类
    import com.alibaba.fastjson.JSONException;
    import com.alibaba.fastjson.JSONObject;
    import com.ectrip.android.bank.Alipay_Pay;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class WxSendPicUtil{
        public static final String appid = "wx0d872f39c7acfd63";
        public static final String secret = "d3b210bbc77749a9c500b86008a5522c";
    
        /**
         * 获得微信 AccessToken
         * access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。
         * 开发者需要access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取
         * 的access_token失效。
         * (此处我是把token存在Redis里面了)
         */
    
        public static AccessToken getWXToken() {
            String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
            JSONObject jsonObject = httpsRequest(tokenUrl, "GET", null);
            AccessToken access_token = new AccessToken();
            if (null != jsonObject) {
                try {
                    access_token.setAccessToken(jsonObject.getString("access_token"));
                    access_token.setExpiresin(jsonObject.getInteger("expires_in"));
                } catch (JSONException e) {
                    access_token = null;
                    e.printStackTrace();
                }
            }
    
            return access_token;
        }
    
        //发送请求,根据code获取openId
        public static String getOpenId(String code) {
            String content = "";
            String openId = "";
            //封装获取openId的微信API
            StringBuffer url = new StringBuffer();
            url.append("https://api.weixin.qq.com/sns/oauth2/access_token?appid=")
                    .append(Alipay_Pay.readxmlparm("APPID"))
                    .append("&secret=")
                    .append(Alipay_Pay.readxmlparm("APPSECRET"))
                    .append("&code=")
                    .append(code)
                    .append("&grant_type=authorization_code")
                    .append("&&connect_redirect=1");
            try {
                JSONObject jsonObject = httpsRequest(url.toString(), "GET", null);
                if (jsonObject.get("openid") != null)
                    openId = jsonObject.get("openid").toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return openId;
        }
    
        /**
         * 发送https请求
         *
         * @param requestUrl    请求地址
         * @param requestMethod 请求方式(GET、POST)
         * @param outputStr     提交的数据
         * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
         */
        public static JSONObject httpsRequest(String sendurl, String method, String str) {
            String myCharset = "UTF-8";
            String jsonStr = null;
            JSONObject jsonObject = null;
            CloseableHttpClient httpclient = null;
            CloseableHttpResponse response = null;
            httpclient = HttpClients.createDefault();
            System.out.println("getOpenIdNew sendUrl:" +
                    sendurl);
            if (!"GET".equals(method)) {
                return null;
            }
            HttpEntity entity = null;
            try {
                HttpGet httpGet = new HttpGet(sendurl);
                response = httpclient.execute(httpGet);
                entity = response.getEntity();
                if (entity != null) {
                    jsonStr = EntityUtils.toString(entity, myCharset);
                    jsonObject = JSONObject.parseObject(jsonStr);
                    return jsonObject;
                }
                EntityUtils.consume(entity);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (response != null) {
                    try {
                        response.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (httpclient != null) {
                    try {
                        httpclient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }
    
        /**
         * 上传本地文件到微信获取mediaId
         */
        public static String upload(String filePath, String accessToken, String type) throws IOException {
    
            File file = new File(filePath);
            StringBuffer buffer = new StringBuffer();
            BufferedReader reader = null;
            String result = null;
            HttpURLConnection con;
            if (!file.exists() || !file.isFile()) {
                System.out.println("文件不存在");
            }
            try {
                //  String url = ConfigUtil.UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE",type);
                String url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type;
                URL urlObj = new URL(url);
                //连接
                con = (HttpURLConnection) urlObj.openConnection();
    
                con.setRequestMethod("POST");
                con.setDoInput(true);
                con.setDoOutput(true);
                con.setUseCaches(false);
    
                //设置请求头信息
                con.setRequestProperty("Connection", "Keep-Alive");
                con.setRequestProperty("Charset", "UTF-8");
    
                //设置边界
                String BOUNDARY = "----------" + System.currentTimeMillis();
                con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
    
                StringBuilder sb = new StringBuilder();
                sb.append("--");
                sb.append(BOUNDARY);
                sb.append("\r\n");
                sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
                sb.append("Content-Type:application/octet-stream\r\n\r\n");
    
                byte[] head = sb.toString().getBytes("utf-8");
    
                //获得输出流
                OutputStream out = new DataOutputStream(con.getOutputStream());
                //输出表头
                out.write(head);
    
                //文件正文部分
                //把文件已流文件的方式 推入到url中
                DataInputStream in = new DataInputStream(new FileInputStream(file));
                int bytes = 0;
                byte[] bufferOut = new byte[1024];
                while ((bytes = in.read(bufferOut)) != -1) {
                    out.write(bufferOut, 0, bytes);
                }
                in.close();
    
                //结尾部分
                byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");//定义最后数据分隔线
    
                out.write(foot);
    
                out.flush();
                out.close();
                //定义BufferedReader输入流来读取URL的响应
                reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }
                if (result == null) {
                    result = buffer.toString();
                }
            } catch (Exception e) {
                System.out.println("上传本地文件到微信异常e:" + e.getMessage());
                System.out.println("上传本地文件到微信获取mediaId异常:" + e);
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }
    
            net.sf.json.JSONObject jsonObj = net.sf.json.JSONObject.fromObject(result);
            System.out.println(jsonObj);
            String typeName = "media_id";
            if (!"image".equals(type)) {
                typeName = type + "_media_id";
            }
            String mediaId = jsonObj.getString(typeName);
            return mediaId;
        }
    
        /**
         * 微信公共账号发送给账号(本方法限制使用的消息类型是语音或者图片)
         *
         * @param mediaId     图片或者语音内容
         * @param toUser      微信用户
         * @param messageType 消息类型
         * @return
         */
    
        public static void sendPicOrVoiceMessageToUser(String mediaId, String toUser, String msgType, String accessToken) {
            String json = null;
            if (msgType.equals("image")) {
                json = "{\"touser\": \"" + toUser + "\",\"msgtype\": \"image\", \"image\": {\"media_id\": \"" + mediaId + "\"}}";
            } else if (msgType.equals("voice")) {
                json = "{\"touser\": \"" + toUser + "\",\"msgtype\": \"voice\", \"voice\": {\"media_id\": \"" + mediaId + "\"}}";
            }
            //获取请求路径
            String action = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken;
            try {
                connectWeiXinInterface(action, json);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 连接请求微信后台接口
         *
         * @param action 接口url
         * @param json   请求接口传送的json字符串
         */
    
        public static void connectWeiXinInterface(String action, String json) {
            URL url;
            try {
                url = new URL(action);
                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(json.getBytes("UTF-8"));// 传入参数
                InputStream is = http.getInputStream();
                int size = is.available();
                byte[] jsonBytes = new byte[size];
                is.read(jsonBytes);
                String result = new String(jsonBytes, "UTF-8");
                JSONObject jsonObject = JSONObject.parseObject(result);
                Object msg = jsonObject.get("errmsg");
                os.flush();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    

    示例:

    展开全文
  • 写这篇文章之前先给大家看张图片,这种图是不是很熟悉,用过微信关注过某些公众号的用户应该都见过,没错,是微信公众号推送出来的。通过消息推送,可以为用户发送预约服务,购买提醒服务,发货服务,提现提醒服务等...

    写这篇文章之前先给大家看张图片,这种图是不是很熟悉,用过微信关注过某些公众号的用户应该都见过,没错,是微信公众号推送出来的。通过消息推送,可以为用户发送预约服务,购买提醒服务,发货服务,提现提醒服务等消息通知。

    现在,我们也要做这样一件事,不过我的业务场景是这样的:现在有一个公众号,还有一个小程序,我需要给指定的已关注我公众号的用户推送一条模板消息,当用户点击模板消息后可以调到我小程序中的指定页面。(本文以此业务场景记录开发过程)

    不了解微信公众号或者没有相关经验的开发人员可能有点懵,因为不知道怎么下手,究竟该如何推送模板消息呢,其实很简单,我们只需要根据微信公众平台技术文档去仔细阅读接口调用方式并按照规范调用即可完成推送。附:模板消息推送接口

    大致阅读文档后,我们知道需要具备以下条件:

    1. 有一个微信公众号,并且知道公众号的appid和appSecret
    2. 有一个小程序,并且知道小程序的appid
    3. 需要跳转到的小程序的页面(不知道的话可以问前端开发人员要)
    4. 知道就模板消息接受者的openid(接受者已关注微信公众号)

    以下附上我们需要用到的两个官方接口:

    //微信获取ACCESS_TOKEN API
    public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";
    
    //微信模板消息推送 API
    public static final String MESSAGE_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

    第一个接口为获取access_token,它是调用接口的凭证,在调用其他接口前必须先调用此接口获取access_token(请将自己的微信公众号的appid和appSecret替换接口地址中的APPID和SECRET)。此接口返回示例如下(返回结果是一个json数据包,注意access_token的有效期为7200s,也就是2小时,且此接口的调用频次为日限2000,如果你的推送用户量大,请把返回的access_token放到缓存中缓存一段时间,节约网络资源,从我做起。:)。另外,调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。

    {
    "access_token":"25_vdgBGnGbfY1bE9e0xOw-mHTROXh6xUXwCANb49jjEQ_Eu4iyhW2MqSmA1UZf7oGelW9AjLGzICvhOJcAqLaxDRVBLmwkeLDEPwQ0YbDN7-wdYza47x-WYDY0lvbFJX3ejIMu6xwnQZGlN2Um1SXHTXSeAD5AHLG",
    "expires_in":7200
    }

    第二个接口即为推送消息模板的关键性接口,模板消息的推送就是依靠此接口完成的,但是注意,需要将第一个接口返回的access_token解析拿出来替换这个接口地址中的ACCESS_TOKEN。(以下为此接口的请求体,封装成一个数据传输对象dto,然后转成json)

    {
               "touser":"OPENID",        // 接收模板消息的用户
               "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",        //公众号中配置的消息模板对应的模板ID
               "url":"http://weixin.qq.com/download",         //想要跳转的路径 
               "miniprogram":{        //需要跳转的小程序的appid和页面
                 "appid":"xiaochengxuappid12345",
                 "pagepath":"index?foo=bar"
               },          
               "data":{        // 封装模板消息数据
                       "first": {
                           "value":"恭喜你购买成功!",
                           "color":"#173177"
                       },
                       "keyword1":{
                           "value":"巧克力",
                           "color":"#173177"
                       },
                       "keyword2": {
                           "value":"39.8元",
                           "color":"#173177"
                       },
                       "keyword3": {
                           "value":"2014年9月22日",
                           "color":"#173177"
                       },
                       "remark":{
                           "value":"欢迎再次购买!",
                           "color":"#173177"
                       }
               }
           }

    注意:请务必根据微信公众平台的技术文档按照规范封装数据请求体

    注:url和miniprogram都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url。

    å°¼çï¼ç«ç¶ç»æäºï¼ï¼ - èè头è£é¼è¡¨æ_表æ头ç_èè头_éé¦é¿è¡¨æ


    这就结束了?并没有!如果我没有公众号我想练练手怎么办呢?当然有办法,我们可以申请测试号直接测试!nice!

    微信公众平台接口测试帐号申请,点此申请测试号!!!

    现在公众号的appid和appSecret有了!

    关注二维码,相当于关注了上面的测试号,这样我们就拿到了自己的openid!

    增加一个模板消息,现在模板ID也有了!

    根据上面的步骤,一步步来,直接放张结果图吧!大功告成!

    (本文最终推送的结果与实际场景有出入,因为本测试号无法关联我要跳转的小程序,所以...)

    文章最后抛出一些注意点:

    1. 如果要在微信公众号内推送消息,其分为微信消息与小程序消息,微信消息可以主动推送,小程序消息的推送依赖于用户主动点击小程序内产生的formid,两者是有差别的,注意区分。(本文推送的是微信消息,所以跟formid没关系)
    2. 如果要推送消息并且跳转对应小程序,需要小程序已审核发布,并且已关联本公众号,否则推送不出来!
    3. 本文发送http请求依赖了hutool工具包,自行pom文件引入调用即可。
    4. 多看文档介绍,调用接口推送完毕回返回状态码,根据状态码自行检查错误。全局返回码说明

    附上本文demo代码:

    public class WxTemplateMessage {
    
        public static void main(String[] args) {
            final Logger logger = LoggerFactory.getLogger(WxTemplateMessage.class);
            logger.info("========微信模板消息定时推送开始========");
            String appId = "wxf8daaba119674993ae";        // 公众号appid
            String appSecret = "2a996e13386170a817c42d611a8b26ce49";      // 公众号appSecret
            String miniAppId = "wx37e7dd9d2312bfb19d4";        // 要跳转的小程序appid
            String pagePath = "pages/common/Outpatient-pay?type=clinic";     // 要跳转的小程序页面
            String accessToken = JSONObject.fromObject(HttpUtil.get(WeChatMessagePushConstants.ACCESS_TOKEN_URL.replace("APPID", appId).replace("SECRET", appSecret))).getString("access_token");
            WechatTemplate template = new WechatTemplate();
            template.setTemplate_id("a5kTd_SzwgUhwRrh21PF7eYIcouGUNaQ8tdRoHgNTC5GE");     // 模板消息ID
            template.setTouser("olfZfwadJ24NRAm7YS2fESXYuFVqmM");     //  接收者openid
            Miniprogram miniprogram = new Miniprogram();
            miniprogram.setAppid(miniAppId);
            miniprogram.setPagepath(pagePath);
            template.setMiniprogram(miniprogram);
            Map<String, TemplateData> mapdata = new HashMap<>();
            TemplateData first = new TemplateData("您好,您有一笔订单产生!");
            mapdata.put("first", first);
    
            TemplateData keyword1 = new TemplateData("测试用户");       // 用户名
            mapdata.put("keyword1", keyword1);
    
            TemplateData keyword3 = new TemplateData("100.00");           // 订单金额
            mapdata.put("keyword3", keyword3);
    
            TemplateData keyword4 = new TemplateData("小米手机");         // 商品信息
            mapdata.put("keyword4", keyword4);
    
            TemplateData remark = new TemplateData("更多详细内容点击查看");         // 备注
            mapdata.put("remark", remark);
            template.setData(mapdata);
    
            logger.info("推送内容:[{}]", com.alibaba.fastjson.JSONObject.toJSONString(template));
            JSONObject pushResult = JSONObject.fromObject(HttpUtil.post(WeChatMessagePushConstants.MESSAGE_TEMPLATE_URL.replace("ACCESS_TOKEN", accessToken), com.alibaba.fastjson.JSONObject.toJSONString(template)));
            int result = 0;
            if (null != pushResult) {
                if (0 != pushResult.getInt("errcode")) {
                    result = pushResult.getInt("errcode");
                    logger.info("推送结果:[推送失败],错误代码:[{}],错误原因:[{}]。", pushResult.getInt("errcode"), pushResult.getString("errmsg"));
                } else {
                    logger.info("推送结果:[推送成功]。");
                }
            }
            logger.info("========微信模板消息定时推送结束========");
        }
    }
    
    public class WeChatMessagePushConstants {
    
        //微信获取ACCESS_TOKEN API
        public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";
    
        //微信模板消息推送 API
        public static final String MESSAGE_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
    
    }
    public class Miniprogram {
    
        private String appid;
    
        private String pagepath;
    
        public String getAppid() {
            return appid;
        }
    
        public void setAppid(String appid) {
            this.appid = appid;
        }
    
        public String getPagepath() {
            return pagepath;
        }
    
        public void setPagepath(String pagepath) {
            this.pagepath = pagepath;
        }
    }
    public class WechatTemplate {
        private String touser;
    
        private String template_id;
    
        private Miniprogram miniprogram;
    
        private String url;
    
        private Map<String, TemplateData> data;
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public Miniprogram getMiniprogram() {
            return miniprogram;
        }
    
        public void setMiniprogram(Miniprogram miniprogram) {
            this.miniprogram = miniprogram;
        }
    
        public String getTouser() {
            return touser;
        }
    
        public void setTouser(String touser) {
            this.touser = touser;
        }
    
        public String getTemplate_id() {
            return template_id;
        }
    
        public void setTemplate_id(String template_id) {
            this.template_id = template_id;
        }
    
        public Map<String, TemplateData> getData() {
            return data;
        }
    
        public void setData(Map<String, TemplateData> data) {
            this.data = data;
        }
    
    }

    å®ç¾_å®ç¾è¡¨æ下期再见!

    展开全文
  • 今天给大家分享的关注公众号自动推送图文消息,以及做一个超牛逼的机器人。 先看看效果。 发错图了。。。这是我昨天开发的一款机器人chu了会骂人啥都不会了。 我今天将它词库进行了更新和升级,接入了...
  • 一般在微信企业号下做软件开发,基本都会用到消息推送,用户在完成一个操作之后,会在企业号中推送一条消息,这条消息可能是文本、图文等不同类型,在具有审批流程的消息推送中,下一级人员审批完成会给上一级推送一...
  • 企业微信消息推送

    2020-06-29 11:17:33
    开发前准备:添加自建应用 登录企业微信管理端 -> 应用与小程序 -> 应用 ->... 创建完成后,在管理端的应用列表里进入...消息推送分为两步: 1获取access_token 2.构造消息体,发送消息 话不多说,直接放代.
  • 然后会自动推送对应的内容给用户。 这个功能在微信开发中, 我们叫它消息管理。 用户除了使用关键词回复之外, 还可以回复图片,用户地理位置,小视频等等。 从这一节课程开始, 子恒老师将跟你...
  • 今天要说的是微信推送消息的详细流程,配合微信开发手册一起使用哦,虽然说开发手册有很多坑,但是我会把消息推送的坑一个一个讲解出来 配置消息推送的接口 我们登陆微信公众平台配置服务器的URL,填写 Token令牌 ...
  • 注册 https://work.weixin.qq.com/wework_admin/register_wx ... ...* 使用普通微信关注后才能接收消息 应用与小程序--->创建应用 * 可见范围可以选整个企业 企业ID 我的企业--->...
  • 接收服务器推送普通消息 接收普通消息 当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。 服务器介入获取微信推送消息代码: /** * 此方法用于微信回复消息 * @param ...
  • thinkphp 5.0 对接微信公众号,向指定用户发送模板消息
  • 微信公众号推送消息,可以分全部粉丝、分组粉丝群发,服务号分组群发每月400次提交,而公众号规定订阅每天只能1次提交,服务号每月40次提交。通过开发公众号高级群发接口可以实现每月400次提交群发。也可以使用微号...
  • C# 企业微信消息推送

    2019-11-19 11:42:41
    企业微信开发API文档链接。 第一步 注册企业微信 只需要填写下基本资料就可以。 第二步 记下企业微信 CorpID 第三步 创建应用,并记下 AgentId与Secret 第四步 写代码实现App内推送消息 ...
  • 完整demo下载 概述 微信公众平台开始支持前端网页,大家可能看到很多网页...微信模板消息推送订单购买成功推送 三、项目结构 四、使用规则 所有服务号都可以在功能-&amp;gt;添加功能插件处看到申请模板消息功能...
  • 微信公共号接收事件推送公共号除了可以接收普通消息,比如文本,图片,音频等,还可以接收事件推送来做出相应的反应。常用的事件有以下几种。1, 关注/取消关注事件,推送的xml数据中没有Content选项,因此去掉$...
  • 企业微信开发第一步获取AccessToken,企业微信的AccessToken和公众号的不一样,企业微信所有接口调用只需要一个AccessToken,而公众号授权和jssdk是分开的 一、获取企业微信AccessToken import ...
  • 其实想给点餐系统加推送很久了,之前也有单门写过Java版的微信消息推送和云开发版的微信消息推送。之所以一直没有加,也是考虑到大家的学习接受度,因为做订阅消息推送是一个综合性的开发工作。 需要你既要会小程序...
  • c#winform开发微信企业号推送文本消息图片,图文,视频,语音等消息
  • 1、概述 在微信用户和公众号产生交互的...我们在上一篇微信公众号开发C#系列-6、消息管理-普通消息接受处理中讲到,微信消息可以大体分为两种类型,一种是包括:文本,语音,图片等的普通消息,另一种就是本篇要将...
1 2 3 4 5 ... 20
收藏数 14,602
精华内容 5,840
关键字:

微信开发推送消息图片