1、场景:
经常看到微信别人分享邀请的各种海报,海报上有小程序码,特别是小程序码,中间是分享人的头像,并不是默认的平台logo。这样设计在UI视觉上更有特色,再则,用头像就能区分是来自不同人分享的,一目了然。
2、微信接口文档:
HTTPS 调用
方式:POST
请求地址:
https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
请求参数
具体文档地址为:
3、实现代码:
参数实体
* @description
*/
@Data
public class QrCodeVo {
/**
* 用户头像
*/
private String avatarImage;
/**
* 域名
*/
private String domainName;
/**
* 小程序appId
*/
private String appId;
/**
* 小程序appSecrect
*/
private String appSecrect;
/**
*
*/
private String model;
/**
*
*/
private String field;
//前端传的参数
/**
* 用户id
*/
private String mobileUserId;
/**
* 小程序模块id
*/
private String objectId;
/**
* 其他参数
*/
private String otherId;
/**
* 扫码进入的页面
*/
private String page;
}
用户方形头像换成圆形头像
* @description
*/
public class CustomQrCodeUtil {
private static Logger LOGGER = LoggerFactory.getLogger(CustomQrCodeUtil.class);
public static String UPLOAD_PATH = "/data/tomcat/webapps/img";
/**
* 用户方形头像换成圆形头像
* @param headImage 用户方形头像
* @param model
* @param field
* @return
* @throws MalformedURLException
*/
public static String circularHeadImage(String headImage,String model,String field,String domainName) throws MalformedURLException {
BufferedImage avatarImage;
try {
avatarImage = ImageIO.read(new URL(headImage));
int width = 400;
BufferedImage formatAvatarImage = new BufferedImage(width, width, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = formatAvatarImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int border = 1;
Ellipse2D.Double shape = new Ellipse2D.Double(border, border, width - border * 2, width - border * 2);
graphics.setClip(shape);
graphics.drawImage(avatarImage, border, border, width - border * 2, width - border * 2, null);
graphics.dispose();
graphics = formatAvatarImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int border1 = 3;
Stroke s = new BasicStroke(4.5F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
graphics.setStroke(s);
graphics.setColor(Color.WHITE);
graphics.drawOval(border1, border1, width - border1 * 2, width - border1 * 2);
graphics.dispose();
String pathFileStr = File.separator + model + File.separator + field + File.separator + DateUtils.getCurrentDate();
IPUtils.createFile(new File(UPLOAD_PATH + pathFileStr));
String imageId = UuidUtils.randomUUID();
String fileName = imageId + ".png";
String destPath = UPLOAD_PATH + pathFileStr + File.separator + fileName;
ImageIO.write(formatAvatarImage, "png", new FileOutputStream(destPath));
LOGGER.info("调用用户方形头像换成圆形头像接口==="+domainName + "/img"+pathFileStr + File.separator + fileName);
return domainName + "/img"+pathFileStr + File.separator + fileName;
} catch (Exception e) {
LOGGER.error("调用用户方形头像换成圆形头像接口异常", e);
}
return null;
}
}
生成小程序码
/**
* @description
*/
public class WxQrcode {
/**
* 生成小程序码
* @param vo
* @return
*/
public static String qrCode(QrCodeVo vo) {
String qrCodeUrl = "";
try{
String circularHeadImage = CustomQrCodeUtil.circularHeadImage(vo.getAvatarImage(),vo.getModel(),vo.getField(),vo.getDomainName());
String accessToken = vo.getToken();
Map<String, Object> params = new HashMap<>();
String scene = vo.getMobileUserId() + "&" + vo.getObjectId();
if(vo.getOtherId() != null){
scene = scene + "&" + vo.getOtherId();
}
System.out.println("scene : " + scene);
params.put("scene", scene);
params.put("page", vo.getPage() != null ? vo.getPage() :"pages/index/index");
params.put("width", 430);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(WeixinUrl.WXACODE_UNLIMIT + accessToken);
httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
StringEntity entity = new StringEntity(JSON.toJSONString(params));
entity.setContentType("image/png");
httpPost.setEntity(entity);
InputStream inputStream = httpClient.execute(httpPost).getEntity().getContent();
String pathFileStr = File.separator + vo.getModel() + File.separator + vo.getField() + File.separator + DateUtils.getCurrentDate();
IPUtils.createFile(new File(CustomQrCodeUtil.UPLOAD_PATH + pathFileStr));
String imageId = UuidUtils.randomUUID();
String fileName = imageId + ".png";
String destPath = CustomQrCodeUtil.UPLOAD_PATH + pathFileStr + File.separator + fileName;
String imageUrl = pathFileStr + File.separator + fileName;
FileOutputStream out = new FileOutputStream(destPath);
byte[] buffer = new byte[8192];
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.flush();
out.close();
BufferedImage b1 = ImageIO.read(new URL(vo.getDomainName()+"/img"+imageUrl));
//将用户头像覆盖小程序码中间的logo
BufferedImage b2 = ImageIO.read(new URL(circularHeadImage));
if (b1 != null) {
//Graphics2D绘图
Graphics2D g = b1.createGraphics();
g.drawImage(b2, 115, 117, 200, 195, null);
g.dispose();
String pathFileStr2 = File.separator + vo.getModel() + File.separator + vo.getField() + File.separator + DateUtils.getCurrentDate();
IPUtils.createFile(new File(CustomQrCodeUtil.UPLOAD_PATH + pathFileStr2));
String uuId = UuidUtils.randomUUID();
String fileName2 = uuId + ".png";
String destPath2 = CustomQrCodeUtil.UPLOAD_PATH + pathFileStr2 + File.separator + fileName2;
ImageIO.write(b1, "png", new File(destPath2));
qrCodeUrl = pathFileStr2 + File.separator + fileName2;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
return qrCodeUrl;
}
}
4、注意:
POST 参数需要转成 JSON 字符串,不支持 form 表单提交。
接口只能生成已发布的小程序的二维码(不是已发布的小程序调用接口会生成损坏的图片,所以小程序要先审核通过一版才可以调试。传入的page必须是已经发布的小程序存在的页面,根路径前不要添加 /,否则也会生成损坏的图片)
调用分钟频率受限(5000次/分钟),如需大量小程序码,建议预生成。
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海