二维码生成以及扫一扫解析二维码原理
1、生成URL,确定要通过二维码传达的信息,也就是通过扫一扫可以获得地址和数据信息
1、// 得到随机数,用随机数得到签名,签名验证身份
String ranString = RandomStringUtils.randomAlphanumeric(10);
2、其他参数信息,在二维码中存储的信息非常有限,所有在微信,支付宝的二维码一般不带参数,而是只包含地址信息,在其地址中就包含相应的信息,微信或者支付宝
//在这一般上送标识字段不上送数据信息,状态字段用于判断什么状态下执行什么操作
String orderNo = "123456";
Map<String, String> maps = new HashMap<String, String>();
maps.put("orderNo", orderNo);
maps.put("xx", xx);
3、// 根据规则生成URL,这个URL就是存放到二维码中的数据
String url = generateUrl(ranString, maps);
System.out.println("生成后的URL为: " + url);
4、生成URL方法
// 扫描二维码需要访问的URL,如果是想访问自己的App,则把相应的APP地址放到二维码中
private static final String BASE_URL = "https://st1.tyest.com/app-server";
/**
* 生成二维码URL地址
* @param paramMaps
* 上送字段map
* @param RanSign
* 随机数
* @return
* @throws Exception
*/
public static String generateUrl(String RanSign, Map<String, String> paramMaps) {
String url = null;
String data = "";
try {
// 拼接业务信息字符串,需要上送的字段信息
for (Iterator<Entry<String, String>> it = paramMaps.entrySet()
.iterator(); it.hasNext();) {
Entry<String, String> entry = it.next();
String inputPartkey = entry.getKey();
String inputPart = entry.getValue();
data += inputPartkey + "=" + inputPart + "&";
}
// 对数据信息加密,可以加密,但是二维码存放不下aes加密后的数据,太大了
/*AES aes = new AES();
String HexString = aes.encrypt(data, AES_KEY);*/
//拼接的字符串多了&,类似data=XXX&sign=XXX
data=(String) data.subSequence(0, data.length()-1);
System.out.println("业务信息字符串: " + data);
// 对业务信息进行签名,得到签名信息,包含上送字段,这就是通过扫一扫后得到地址后面一串很长的字符串
String sign = SHA1.genSign(RanSign);
System.out.println("签名: " + sign);
// 后面的则是需要访问的具体的接口,以及需要上送的参数,上送字段可以选择是否加密
url = BASE_URL + "/test/testInterface?sign=" + sign + "&data=" + data;
} catch (Exception e) {
e.printStackTrace();
}
return url;
}
5、绘制二维码
// 根据URL生成二维码图片,把上面的URL以及参数信息写到二维码中,添加logo图片的路径
String logoPath = "D:\\testbail.png";
BufferedImage image = QrCodeImgUtil.qrCodeEncode(url, logoPath);
// 得到outputStream把数据信息写出来
OutputStream out = new FileOutputStream(new File("D:\\testbail.png"));
//把图片绘制到给出的画板上
ImageIO.write(image, "png", out);
System.out.println("图片生成完成");
System.out.println("ranString=" + ranString);
6、绘制方法,网上其实有很多的类似方法,不过还是说下吧
public static BufferedImage qrCodeEncode(String encodeddata,String logoPath)
throws IOException {
Qrcode qrcode = new Qrcode();
// 纠错级别(L 7%、M 15%、Q 25%、H 30%)和版本有关
qrcode.setQrcodeErrorCorrect('M');
qrcode.setQrcodeEncodeMode('B');
qrcode.setQrcodeVersion(7); // 设置Qrcode包的版本
byte[] d = encodeddata.getBytes("utf-8"); // 字符集
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 创建图层
Graphics2D g = bi.createGraphics();
g.setBackground(Color.WHITE); // 设置背景颜色(白色)
g.clearRect(0, 0, width, height); // 矩形 X、Y、width、height
g.setColor(Color.BLACK); // 设置图像颜色(黑色)
if (d.length > 0 && d.length < 123) {
boolean[][] b = qrcode.calQrcode(d);
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b.length; j++) {
if (b[j][i]) {
g.fillRect(j * 3 + 2, i * 3 + 2, 3, 3);
}
}
}
}
/* 添加logo图片 */
if(logoPath!=null){
int width_4 = width / 4;
int width_8 = width_4 / 2;
int height_4 = height / 4;
int height_8 = height_4 / 2;
Image img = ImageIO.read(new File(logoPath));
g.drawImage(img, width_4 + width_8, height_4 + height_8,width_4,height_4, null);
g.dispose();
bi.flush();
}
g.dispose(); // 释放此图形的上下文以及它使用的所有系统资源。调用 dispose 之后,就不能再使用 Graphics 对象
bi.flush(); // 刷新此 Image 对象正在使用的所有可重构的资源
return bi;
}
6、打开D:\\testbail.png生产的二维码图片,通过扫一扫可以得到如下的类似信息
https://st1.tyest.com/app-server/test/testInterface?sign=a094bb8f56bd2beac35949a76e2ca35dd6e69c87&orderNo=123456
这个就是我们常见的URL了,通过浏览器就可以访问了。
2、 二维码的解析:
1、代码解析二维码图片
//解析的二维码路径
String imgPath = "D:\\testbail.png";
File imageFile = new File(imgPath);
// 测试解析二维码图片内容
String decoderContent = QrCodeImgUtil.qrCodeDecode(imageFile);
System.out.println(decoderContent);
System.out.println("=========解码成功===========");
首先我们要知道,代码解析会解析图片上的所有信息,当然包括图片信息,
然而图片logo是外加入的,所以通过代码解析不了带有logo的二维码,这一点
我还没想到怎么做,有知道的
相关实现方法:
/**
* 解析二维码,返回解析内容
*
* @param imageFile
* @return
*/
public static String qrCodeDecode(File imageFile) {
String decodedData = null;
QRCodeDecoder decoder = new QRCodeDecoder();
BufferedImage image = null;
try {
image = ImageIO.read(imageFile);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
try {
decodedData = new String(decoder.decode(new J2SEImage(image)),"utf-8");
} catch (DecodingFailedException dfe) {
System.out.println("Error: " + dfe.getMessage());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return decodedData;
}
得到结果:
https://st1.tyest.com/app-server/test/testInterface?sign=d4b8ae6e19daf14fb8dbaac9ce6ce9bc6f8679f5&orderNo=123456
=========解码成功===========
2、通过扫一扫工具解析(最简单的一种解析方式)
3、扫描二维码背后的故事:
通过上面的方式我们生产了我们自己的二维码,通过扫一扫就可以访问我们自己的系统实现相应的功能,
在这里我们模拟实现一下
String sign = "82385294b5eee3adb2fcedcf0868a219e0e69e1f";
String data = "orderNo=123456";
String ranString ="GJ5U6PfwbyvA8WZxEJt8s7rKqYQzEl6v";
// 假设该方法就是我们定义的接口,而这两个参数正式通过扫一扫获得数据信息。模拟调接口
testInterface(ranString, sign, data);
private static void testInterface(String ranString, String sign, String data) {
// 首先我们验证签名信息,正确则继续,否则验证不通过,二维码有误,在这里我们就知道了,用支付宝或者微信扫描彼此的二维码,就会提示无效的二维码
// 就是因为在验签的时候失败了,就无法继续
if (SHA1.verifySign(ranString, sign)) {
// 验签成功
// 对数据信息解密,如果数据加密的话
AES aes = new AES();
try {
String deString = aes.decrypt(data, AES_KEY);
System.out.println(deString);
// 做相应的业务处理逻辑
} catch (CryptException e) {
e.printStackTrace();
}
} else {
//扫二维码验签失败,说明不是可处理的二维码
System.out.println("二维码有误!");
}
}
扫描二维码就是访问接口,和我们平时写的接口一样的道理,多看看就会明白。
在我的资源里上传了二维码的代码,有需要的支持下,有不当之处,望各位猿友之处,万分感谢。
通过此实例,相信对二维码有了进一步的认识。
每天努力一点,每天都在进步。