在获取二维码之前我们首先要获取到access_token。
官方接口:https://api.weixin.qq.com/cgi-bin/token?appid= ‘’&secret=’’ ;
appid和secret就是小程序的appid和密钥,可以在微信公众号平台上面查看自己的小程序信息。
在这里我使用的官方接口:
https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=" + access_token
还需要传递两个参数二维码生成的页面,和二维码的宽度
注意这两个参数的传递格式是json格式的:
data:{
"path":"pages/index/index?query=' ' ",
"width":120
}
这两个接口在前端也可以直接使用生成二维码,但是发布在线上的小程序就不能生成二维码了,因为接口请求的不能是https://api.weixin.qq.com
这里我们需要在后端处理生成二维码接口,具体后端代码如下图所示:
@SuppressWarnings("resource")
@ApiOperation(value = "生成二维码", notes = "发送到前端")
@ApiImplicitParam(name = "id", value = "id", paramType = "query", required = true, dataType = "Long")
@RequestMapping("/getCode")
private void getCode(@RequestParam Long id, HttpServletResponse response) throws IOException {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
String grant_type = "client_credential";
String appid = " "; //你的appid
String secret = " "; //你的密钥
String param = "grant_type=" + grant_type + "&appid=" + appid + "&secret=" + secret;
String ft = HttpRequest.sendGet("https://api.weixin.qq.com/cgi-bin/token", param);
// 解析相应内容(转换成json对象)
JSONObject json = JSON.parseObject(ft);
// 拿到accesstoken
String access_token = (String) json.get("access_token");
String path = "pages/index/index?id=" + id;
int width = 110;
String params = "{\"path\":\"" + path + "\",\"width\":" + width + "}";
params = JSON.parseObject(params).toJSONString();
BufferedImage image = HttpRequest
.postWechatImage("https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=" + access_token, params);
ImageIO.write(image, "JPEG", response.getOutputStream());
}
这里此接口返回给前端的直接就是二维码的图片。
postWechatImage方法的实现如下:
/**
* 请求微信二维码图片 返回BufferedImage
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return BufferedImage
*/
public static BufferedImage postWechatImage(String url, String param) {
PrintWriter out = null;
InputStream inputStream = null;
BufferedImage image = null;
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
inputStream = conn.getInputStream();
image = ImageIO.read(inputStream);
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
return image;
}
2.前端实现过程:
// 生成页面的二维码
uni.request({
url: "https://wx.zzsnqyjxh.org/test/app/user/getCode?id=" + that.id,
// url: 'http://192.168.1.166:9001/test/app/user/getCode?id=' + that.id,
method: "POST",
success(res) {
that.qrcode ='https://wx.zzsnqyjxh.org/test/app/user/getCode?id='+ that.id; //这个接口就是图片地址
// 转化成base64为保存
that.codeTobase64(that.qrcode);
}
});
}
转化为base64是用于绘制画布,绘制画布时不能是在线图片地址
绘制画布保存二维码的代码如下:
//先对图片进行处理
// 转化二维码
// 绘制网略图片
var codePath = wx.env.USER_DATA_PATH + '/goods' + 'invite' + '.png'; //创建名为invite的本地文件
var codeData = this.codetoBase64Url.replace(/^data:image\/\w+;base64,/, ""); //清除base64前缀
var ft = wx.getFileSystemManager(); //获得文件系统管理器 用于操作临时文件
完整的小程序保存二维码的代码如下:
//小程序端保存图片
saveImage() {
uni.showLoading({
title: '图片绘制中...',
})
// 转化二维码
// 绘制网略图片
var codePath = wx.env.USER_DATA_PATH + '/goods' + 'invite' + '.png'; //创建名为invite的本地文件
var codeData = this.codetoBase64Url.replace(/^data:image\/\w+;base64,/, ""); //清除base64前缀
var ft = wx.getFileSystemManager(); //获得文件系统管理器 用于操作临时文件
const context = uni.createCanvasContext('myCanvas')
context.setFillStyle('#FFFFFF')
context.setFillStyle('#1E1E1E') //文字颜色:默认黑色
context.setFontSize(16); //设置字体大小,默认10
context.textAlign = 'center' // 设置位置
context.font = 'normal bold 12px sans-serif'; // 字体样式
context.fillText(this.goodsName, 100, 265, 200, 20);
context.setFillStyle('#FF0060');
context.fillText('抢购价:' + '¥' + this.price, 50, 290, 200, 20);
context.drawImage("../../static/discount.png",100,270,120,24);
context.setFillStyle('#FFFFFF');
context.fillText("再享最高6折优惠",160, 285,132,24);
ft.writeFileSync(codePath, codeData, "base64"); //文件路径 存入内容 编码格式 可以直接使用imgPath来进行操作
context.drawImage(codePath, 100, 300, 106, 106); //二维码
// 绘制网略图片
var goodsPath = wx.env.USER_DATA_PATH + '/goods' + 'dalaba' + '.png'; //创建名为invite的本地文件
var imgData = this.toBase64Url.replace(/^data:image\/\w+;base64,/, ""); //清除base64前缀
var fst = wx.getFileSystemManager(); //获得文件系统管理器 用于操作临时文件
fst.writeFileSync(goodsPath, imgData, "base64"); //文件路径 存入内容 编码格式 可以直接使用imgPath来进行操作
context.drawImage(goodsPath, 20, 0, 250, 250); //图片
//重点:这边本来保存图片是写在draw之后,但第一次保存时空白,第二次才生效,写在draw回调里面就OK了。
context.draw(false, function() {
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
success: function(res) {
uni.hideLoading()
// console.log(res.tempFilePath)
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function(res) {
uni.showToast({
title: '图片已保存'
})
}
})
}
})
})
},
3.将图片转化为base64为的代码如下:
urlTobase64(url) {
var toBase64Url;
uni.request({
url: url,
method: 'GET',
responseType: 'arraybuffer',
success: async res => {
let base64 = wx.arrayBufferToBase64(res.data); //把arraybuffer转成base64
toBase64Url = 'data:image/jpeg;base64,' + base64; //不加上这串字符,在页面无法显示
}
});
},