微信公众号-java上传图片素材到微信服务器&基于事件推送两条消息

微信公众号-java上传图片素材到微信服务器&基于事件推送两条消息

场景:基于微信扫码登录/关注事件,向用户推送两条消息。
分析:翻阅了微信开发者文档和一些其他资料发现,公众号针对用户关注/扫码/取关等特定事件,允许开发者回复用户(详细描述参看公众号开发文档)。但是,对于事件允许回复用户一条消息(被动回复),那么发送两条消息的话,需要主动向用户推送一条消息。另外,推送图片、语音、视频等素材需要先将素材上传至微信服务器。下面是一个demo:


提示:以下是本篇文章正文内容,下面案例可供参考

一、上传图片素材至微信服务器

页面效果
已上传至公众号

1.前端(bootstrap)


<body style="width: 100px;height: 100px">
<div >
    <table class="table" id="specialInfoTable" style="">
        <tbody>
        <#--上传文件区域-->
        <tr id="copyContainer">
            <td>
                <div class="col-md-12">
                    <div class="form-group">
                        <label class="col-sm-3 control-label no-padding-right">上传图片</label>
                        <div class="col-sm-9" style="width:80.5%">
                            <input id="imgUpload" type="file" name="media" class="btn btn-primary"/>
                            <label style="margin-top:5px;"/>
                        </div>
                    </div>
                </div>
                <div class="col-md-12">
                    <label class="col-sm-3 control-label no-padding-right">转换内容</label>
                    <input type="text" id="specialInfoBgimg" readonly="readonly" class="form-control" name="bgimg" id="" value="" />
                </div>
            </td>
        </tr>
        </tbody>
    </table>
</div>
</body>

<script src="https://cdn.bootcss.com/bootstrap-fileinput/4.4.7/js/fileinput.min.js"></script>
<script>
    var uploadDefaults = {
        language: 'zh', //设置语言
        uploadAsync : false, //设置异步上传
        showUpload: false, //是否显示上传按钮
        showCaption: false,//是否显示标题
        maxFileSize : 20000, //上传文件大小(KB)
        maxPreviewFileSize : 10000,
        previewFileType : ['image','text','pdf'],
        showUploadedThumbs : false,
        allowedFileTypes : ['image','audio','object'],//允许上传的文件类型
        allowedFileExtensions : ["mp3",'jpg', 'png','svg','ttf','woff']//接收的文件后缀
    };
    //初始化fileinput控件(第一次初始化)
    function initFileInput(id,options) {
        var control = $('#' + id);
        if(!options.uploadUrl){
            console.error('uploadUrl must not be null!');
            return false;
        }
        control.fileinput($.extend({},uploadDefaults,options));
    }

    $(function() {
        var options = {
            uploadUrl: mpath + "/ie/mp/uploadMediaToWechat",
            allowedFileExtensions: ['jpg', 'jpeg', 'png', 'gif', 'swf'],
            allowedFileTypes: null,
            showRemove: false,
            showClose: false
        };
        initFileInput('imgUpload',options);
        $('#imgUpload').on('fileuploaded', function(event, data, previewId, index) {
            var form = data.form, files = data.files, extra = data.extra,
                data = data.response, reader = data.reader;
            if(data.success){
               //key = data.preFilePath;
                key = data.obj;
                $('#specialInfoBgimg').val(key);
                success(data.msg);
                success(data.msg);
            }else{
                error(data.msg);
            }
        });
    });
</script>

2.后端


@RequestMapping("/m/ie/mp")
@RestController
public class WXContentController {
    // 上传微信永久素材的url
    private static final String UPLOAD_FOREVER_MEDIA_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE";


    private static final long MAX_SIZE = 1024 * 1024 * 10;

    private static final String SUPPORTED_FORMAT = "bmp,png,jpeg,jpg,gif";

    @Autowired
    private WeiXinServiceApi weiXinServiceApi;
    @Value("${weixin.button.appid}")
    private String MP_APPID;

    /**
     * 上传素材到微信素材库
     *
     * @param file
     */
    @PostMapping(value = "uploadMediaToWechat")
    public ResultData uploadMediaToWechat(@RequestParam("media") MultipartFile file) throws Exception {

        String[] split = file.getOriginalFilename().split("\\.");
        String suffixName = split[split.length - 1];
        boolean validPic = this.isValidPic(file.getSize(), suffixName);

        if (!validPic) {
            return ResultData.result(false).setMsg("图片素材上传失败");
        }

        // 获取access_token,如果你不会获取,那么这篇博客不适合你。
        // 这步在你的IDE上会提示报错,请修改为你自己获取access_token的方式
        AccessToken accessToken = weiXinServiceApi.getAccessToken(MP_APPID);
        String token = accessToken.getAccessToken();
        System.out.println("token===="+token);
        String replacedUrl = UPLOAD_FOREVER_MEDIA_URL
                .replace("ACCESS_TOKEN", token)
                .replace("TYPE", "image");
        JSONObject jsonObject = UpoladWXFileUtil.uploadFile(replacedUrl,
                file.getInputStream(), file.getOriginalFilename());

        System.out.println("微信素材上传结果:[{}]=" + jsonObject.toString());
        if (jsonObject != null && jsonObject.containsKey("media_id")) {
            return ResultData.result(true).setMsg("上传成功").setObj(jsonObject.getString("media_id"));
        }
        return ResultData.result(false).setMsg("图片素材转换失败");
    }

    /**
     * 图片是否符合微信规范
     *
     * @param size
     * @param suffixName
     * @return
     */
    public Boolean isValidPic(long size, String suffixName) {

        if (size > MAX_SIZE) {
            System.out.println("文件太大,文件的大小最大为2M,请重新上传!");
            return false;
        }

        if (!Arrays.asList(SUPPORTED_FORMAT.split(",")).contains(suffixName)) {
            System.out.println("图片格式不支持,请选择bmp/png/jpeg/jpg/gif的任意一种!");
            return false;
        }
        return true;
    }
}

二、消息推送

1.controller

/**
	 *
	 * @description 接收事件并处理微信通知。<br/>
	 * 有多种微信通知类型,可以在在业务中实现统计、发送消息等操作.
	 */
	@RequestMapping(value = "/event", method = { RequestMethod.POST })
	public void handleEventNofify(@RequestBody String content, HttpServletResponse resp) throws Exception {
		resp.setCharacterEncoding("utf-8");
		String respTxt = weiXinServiceApi.processNotify(content);
		logger.info("handleEventNofify content = {}",content);
		if (respTxt != null)
			resp.getWriter().write(respTxt);
	}

2.service

//处理通知的业务处理方法
@Override
    public String processNotify(String content) throws Exception {

        Map<String, String> root = WXPayUtil.xmlToMap(content);
        String fromUserName = root.get("FromUserName");
        // 获取接收方
        String toUserName = root.get("ToUserName");
        // 获取消息的类型
        String msgType = root.get("MsgType");

        logger.info("receive wx msg {}", root);

        if (msgType.equals(BaseEvent.MESSAGE_TYPE_EVENT)) {
            String eventType = root.get("Event").toLowerCase();
            // 关注事件,用户未关注时,进行关注后的事件推送
            String now = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            if (eventType.equals(BaseEvent.EVENT_TYPE_SUBSCRIBE)) {
                String eventKey = root.get("EventKey");
                handlePostMessage(194,fromUserName);
                return processSubscribe(fromUserName, toUserName, now);
            } else if (eventType.equals(BaseEvent.EVENT_TYPE_SCAN)) {
                // 扫描二维码事件,用户已关注时的事件推送
                String eventKey = root.get("EventKey");
                handlePostMessage(195,fromUserName);
                return handleScan(fromUserName, toUserName, now);
            } else if (eventType.equals(BaseEvent.EVENT_TYPE_UNSUBSCRIBE)) {
                return "";
            }
        }
        return "";
    }

//处理关注的方法
private String processSubscribe(String fromUserName, String toUserName, String now) {
        //从db中获取消息内容,封装成微信的格式
        WeixinReply reply = weixinReplyDao.selectByPrimaryKey(2);
        return "<xml><ToUserName><![CDATA[" + fromUserName + "]]></ToUserName><FromUserName><![CDATA[" + toUserName
                + "]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA["
                + reply.getReplyContent() + "]]></Content></xml>";
    }

//处理扫码
private String handleScan( String fromUserName, String toUserName, String now) {
        return "<xml><ToUserName><![CDATA[" + fromUserName + "]]></ToUserName><FromUserName><![CDATA[" + toUserName
                + "]]></FromUserName><CreateTime>" + System.currentTimeMillis()
                + "</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + reply.getReplyContent()
                + "]]></Content></xml>";
    }
    
//主动推送消息(图片消息,其他消息类型参考公众号文档进行扩展)
private void handlePostMessage(Integer applyId, String fromUserName) {
        try {
            WeixinReplyExample example = new WeixinReplyExample();
            example.createCriteria().andIdEqualTo(applyId);
            List<WeixinReply> replies = weixinReplyDao.selectByExample(example);
            String respMessage = WXReplyMessageUtil.initiativeMsgData(fromUserName, replies.get(0));
            logger.info("图片信息{}", respMessage);
            AccessToken accessToken = getAccessToken(MP_APPID);
            System.out.println("accessToken===" + accessToken.getAccessToken());
            //推送给关注者
            String post = HttpUtils.post("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken.getAccessToken(), respMessage);
            System.out.println("关注/扫码事件后推送信息======" + post);
        } catch (Exception e) {
            logger.error("事件后触发消息异常={}",e);
        }
    }

util

public class WXPayUtil {

	/**
	 * XML格式字符串转换为Map
	 */
	public static Map<String, String> xmlToMap(String strXML) throws Exception {
		try {
			Map<String, String> data = new HashMap<String, String>();
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
			InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
			org.w3c.dom.Document doc = documentBuilder.parse(stream);
			doc.getDocumentElement().normalize();
			NodeList nodeList = doc.getDocumentElement().getChildNodes();
			for (int idx = 0; idx < nodeList.getLength(); ++idx) {
				Node node = nodeList.item(idx);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					org.w3c.dom.Element element = (org.w3c.dom.Element) node;
					data.put(element.getNodeName(), element.getTextContent());
				}
			}
			try {
				stream.close();
			} catch (Exception ex) {
				// do nothing
			}
			return data;
		} catch (Exception ex) {
			WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}",
					ex.getMessage(), strXML);
			throw ex;
		}
	}
}


public class WXReplyMessageUtil {
    /**
     * 主动推送消息
     *
     * @param fromUserName
     * @param wr
     * @return
     */
    public static String initiativeMsgData(String fromUserName, WeixinReply wr) {
        String respMessage = "";
        //图片消息
        ImageMsg iMsg = new ImageMsg();
        iMsg.setTouser(fromUserName);
        iMsg.setMsgtype("image");
        HashMap<String, String> media = new HashMap<>(8);
        media.put("media_id", wr.getReplyContent());
        iMsg.setImage(media);
        respMessage = JSON.toJSONString(iMsg);
        return respMessage;
    }
}
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

最终结果

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值