通过生成带参二维码,将用户的openid获取的同时做为参数,生成后,另一个用户扫码该二维码,系统可以获取到新用户openid的同时,也能标识着是哪个用户被扫码了.
通过上图可以看到,当A君关注B君展示的推广二维码关注微信平台后,可以获取到同样包含B君的A君的一些信息.
假如要做一个功能,将A君的openid绑定到B君的数据下面,即B君邀请了哪些人可以进行查看,则需要在对应着的B君的用户数据表的关联表(如粉丝表)中进行A君的数据记录,这里可以只记录openid.
这里要注意: 如果A君重复扫B君的推广二维码,就会出现重复的数据.
[解决重复关注] 当A君之前未关注,扫码B君的推广二维码时,在EventKey字段含有qrscene_字眼,也就是,当判定该EventKey(新关注者)的字段openid前是否有这个qrscene_
如果有呢,则说明是处于未关注微信平台时扫码关注的.继而再去B的粉丝表中查询是否有该openid,如果有呢,则说明之前已经通过B君的推广二维码进行了关注,则不予给B君
推广奖励.反之则给予奖励.
[新用户的推广二维码生成] A君的openid前含有qrscene_,并且B君粉丝表之前没有过该openid,则进行粉丝表的数据插入,将A君openid插入进去,并给B君奖励,同时,做为新关注
的A君,此时微信平台应该弹出A君的推广二维码了.
DefaultMessageHandler:
@Override public String invoke(ServletInputStream inputStream) throws WeixinException { try { //将输入流转换为字符串 String xmlMsg = XStreamFactory.inputStream2String(inputStream); if (Configuration.isDebug()) { System.out.println("获取POST的消息:"); System.out.println(xmlMsg); System.out.println("------------------------"); /** * 获取扫码时的用户数据,EventKey (包含扫码登录和扫码推广二维码) */ try { System.out.println("test"); Map<String, String> xmlMap = MapUtil.xmlToMap(xmlMsg); System.out.println("xmlMap.get(\"ToUserName\"):"+xmlMap.get("ToUserName")); if(xmlMap.get("ToUserName")!=null){ xmlObj = new ScanQrcodeXml(); xmlObj.setToUserName(xmlMap.get("ToUserName"));//wechat Original id xmlObj.setFromUserName(xmlMap.get("FromUserName"));//openid System.out.println(xmlObj.getFromUserName()); scanQrcodeXmlLoader.setScanQrcodeXml(xmlObj); if(xmlMap.get("EventKey")!=null && xmlMap.get("EventKey").startsWith("qrscene_")){ System.out.println("xmlMap.get(\"EventKey\"):"+xmlMap.get("EventKey")); xmlObj.setEventKey(xmlMap.get("EventKey")); scanQrcodeXmlLoader.setScanQrcodeXml(xmlObj); } } } catch (Exception e) { e.printStackTrace(); } } return this.invoke(xmlMsg); } catch (IOException ex) { throw new WeixinException("输入流转换错误:", ex); } }
以上代码中的获取FromUserName和EventKey等可以获取到扫码登录时的用户信息和扫码关注推广二维码的用户信息及EventKey(内含有openid)
结合"扫码场景关注事件"将含有qrscene_的EventKey用户进行推广二维码的生成,并对不含有qrscene_的用户做出"请勿重复扫码"的友情提示.
DefaultEventMessageHandler:
@Override public OutputMessage qrsceneSubscribe(QrsceneSubscribeEventMessage msg) { TextOutputMessage out = new TextOutputMessage(); out.setContent("扫码场景关注事件"); //TODO 在这里执行A君的推广二维码图片生成及推送 return out; }
最终,不要忘记,当用户未关注时,扫推广二维码会收到以上事件,需要的是再去B君的粉丝表查看该用户之前是否已经通过B君做了扫码关注.
其实这样也不妥当,因为你阻止不了他关注了这个,取关,又去关注C君.
所以当用户第一次关注时,就该把用户数据记录到用户表里,A君扫码推广二维码时,先要去用户表去查是否有该用户已经在用户表中,有的话
则不予B君奖励,并提示"请勿重复关注",否则将发送推广二维码给A君.
微信平台也可以提示: 回复"推广" 或点击某个菜单按钮 可以获取 推广二维码.
现在A君关注B君的推广二维码,关注平台后,也会立即收到一个A自身参数的推广二维码:
做了一个工具类封装:
QrcodeSpreadUtil :
package com.baigehuidi.demo.weixin4j.util; import com.baigehuidi.demo.loader.WeixinInsLoader; import com.baigehuidi.demo.weixin4j.WeixinException; import com.baigehuidi.demo.weixin4j.model.message.MediaType; import com.baigehuidi.demo.weixin4j.model.qrcode.Qrcode; import com.baigehuidi.demo.weixin4j.model.qrcode.QrcodeType; import java.awt.image.BufferedImage; import java.io.File; import java.util.Date; /** * TODO 待完善将D:盘符下的图片(底部海报)改为参数传入.(涉及到Weixin类) 2018-12-19 */ public class QrcodeSpreadUtil { /** * 该方法将用户A扫码用户B后,关注微信平台时,可以获取到一个含有A自身openid参数的推广二维码 * @param openid 传入用户的openid * @return 新的二维码图片的MediaId */ public static String getNewQrcodeMediaId(String openid) { Qrcode qrcode = null; String qrcodeUrl = null; String picUrlOnServer = null; String imgMediaId = null; try { //永久二维码过期时间不会被加入参数 qrcode = WeixinInsLoader.getWeixinInstance().qrcode().create(QrcodeType.QR_LIMIT_STR_SCENE, openid, 99); //获取推广二维码图片URL // qrcodeUrl = WeixinInsLoader.getWeixinInstance().qrcode().showQrcode(qrcode.getTicket()); //将二维码图片保存 //图片保存地址: 从weixin4j.properties中获取保存路径,图片格式为.jpg picUrlOnServer = WeixinInsLoader.getWeixinInstance().getWeixinConfig().getQrcodeSaveUrl() + new Date().getTime() + openid + ".jpg"; //保存单纯的推广二维码到服务器路径 WeixinInsLoader.getWeixinInstance().qrcode().saveQrcode(qrcode.getTicket(), picUrlOnServer); /** * 设置图片重叠,将二维码放到推广海报上. */ //顶部二维码 BufferedImage top = ModifyImageUtil.loadImageLocal(picUrlOnServer); //底部海报 BufferedImage bottom = ModifyImageUtil.loadImageLocal("D:/img/action-adventure-flight-918648.jpg"); //生成带海报的二维码,x,y值需要根据前端设定 String qrcodeImgUrl = ModifyImageUtil.writeImageLocal(picUrlOnServer, ModifyImageUtil.modifyImageTogether(top, bottom, 220, 220)); //上传至微信服务器素材中心,获取图片的mediaId 用户回复给用户 imgMediaId = WeixinInsLoader.getWeixinInstance().media().upload(MediaType.Image, new File(qrcodeImgUrl)); System.err.println("imgMediaId:" + imgMediaId); return imgMediaId; } catch (WeixinException e) { e.printStackTrace(); return null; } } }
上面的海报执行多次也会将用户头像附加上去,用户头像默认是正方形,可以使用一个工具类将方形图片转换成圆形.
/* 之下为新加的方法,将图片处理为圆形图片 */ public static BufferedImage transferImgForRoundImage(String url){ BufferedImage resultImg = null; try { if (StringUtils.isEmpty(url)) { return null; } BufferedImage buffImg1 = ImageIO.read(new File(url)); resultImg = new BufferedImage(buffImg1.getWidth(), buffImg1.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g = resultImg.createGraphics(); Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, buffImg1.getWidth(), buffImg1.getHeight()); //使用setRenderingHint 设置抗锯齿 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); resultImg = g.getDeviceConfiguration().createCompatibleImage(buffImg1.getWidth(), buffImg1.getHeight(), Transparency.TRANSLUCENT); g = resultImg.createGraphics(); // 使用 setRenderingHint 设置抗锯齿 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setClip(shape); g.drawImage(buffImg1, 0, 0, null); g.dispose(); }catch(MalformedURLException e){ e.printStackTrace(); System.err.println("MalformedURLException in ModifyImageUtil.java"); }catch(IOException e){ e.printStackTrace(); System.err.println("IOException in ModifyImageUtil.java"); } return resultImg; }