Java二维码登录流程实现代码(包含短地址生成,含部分代码)
|
近年来,二维码的使用越来越风生水起,笔者最近手头也遇到了一个需要使用二维码扫码登录网站的活,所以研究了一下这一套机制,并用代码实现了整个流程,接下来就和大家聊聊二维码登录及的那些事儿。 二维码原理 二维码是微信搞起来的,当年微信扫码二维码登录网页微信的时候,感觉很神奇,然而,我们了解了它的原理,也就没那么神奇了。二维码实际上就是通过黑白的点阵包含了一个url请求信息。端上扫码,请求url,做对应的操作。 一般性扫码操作的原理 微信登录、支付宝扫码支付都是这个原理: 1. 请求二维码 桌面端向服务器发起请求一个二维码的。 2. 生成包含唯一id的二维码 桌面端会随机生成一个id,id唯一标识这个二维码,以便后续操作。 3. 端上扫码 移动端扫码二维码,解chu出二维码中的url请求。 4. 移动端发送请求到服务器 移动端向服务器发送url请求,请求中包含两个信息,唯一id标识扫的是哪个码,端上浏览器中特定的cookie或者header参数等会标识由哪个用户来进行扫码的。 5. 服务器端通知扫码成功 服务器端收到二维码中信息的url请求时,通知端上已经扫码成功,并添加必要的登录Cookie等信息。这里的通知方式一般有几种:websocket、轮训hold住请求直到超时、隔几秒轮训。 二维码中url的艺术 如何实现自有客户端和其他客户端扫码(如微信)表现的不同 比如,在业务中,你可能想要这样的操作,如果是你公司的二维码被其他app(如微信)所扫描,想要跳转一个提示页,提示页上可以有一个app的下载链接;而当被你自己的app所扫描时,直接进行对应的请求。 这种情况下,可以这样来做,所有二维码中的链接都进行一层加密,然后统一用另一个链接来处理。 如:www.test.com/qr?p=xxxxxx,p参数中包含服务器与客户端约定的加解密算法(可以是对称的也可以是非对称的),端上扫码到这种特定路径的时候,直接用解密算法解p参数,得到www.testqr.com/qrcode?key=s1arV,这样就可以向服务器发起请求了,而其他客户端因为不知道这个规则,只能直接去请求www.test.com/qr?p=xxxxxx,这个请求返回提示页。 如何让二维码更简单 很多时候,又要马儿跑,又要马儿不吃草。想要二维码中带有很多参数,但是又不想要二维码太复杂,难以被扫码出来。这时候,就需要考虑如何在不影响业务的情况下让二维码变的简单。
示例代码 生成二维码(去掉白边,增加中间的logo) 需要导入jar包:zxing的 core-2.0.jar
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class QrCodeUtil {
private static final int BLACK = Color.black.getRGB();
private static final int WHITE = Color.WHITE.getRGB();
private static final int DEFAULT_QR_SIZE = 183;
private static final String DEFAULT_QR_FORMAT = "png";
private static final byte[] EMPTY_BYTES = new byte[0];
public static byte[] createQrCode(String content,int size,String extension) {
return createQrCode(content,size,extension,null);
}
/**
* 生成带图片的二维码
* @param content 二维码中要包含的信息
* @param size 大小
* @param extension 文件格式扩展
* @param insertImg 中间的logo图片
* @return
*/
public static byte[] createQrCode(String content,String extension,Image insertImg) {
if (size <= 0) {
throw new IllegalArgumentException("size (" + size + ") cannot be <= 0");
}
ByteArrayOutputStream baos = null;
try {
Map<EncodeHintType,Object> hints = new HashMap<EncodeHintType,Object>();
hints.put(EncodeHintType.CHARACTER_SET,"utf-8");
hints.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.M);
//使用信息生成指定大小的点阵
BitMatrix m = new MultiFormatWriter().encode(content,BarcodeFormat.QR_CODE,hints);
//去掉白边
m = updateBit(m,0);
int width = m.getWidth();
int height = m.getHeight();
//将BitMatrix中的信息设置到BufferdImage中,形成黑白图片
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
image.setRGB(i,j,m.get(i,j) ? BLACK : WHITE);
}
}
if (insertImg != null) {
// 插入中间的logo图片
insertImage(image,insertImg,m.getWidth());
}
//将因为去白边而变小的图片再放大
image = zoomInImage(image,size);
baos = new ByteArrayOutputStream();
ImageIO.write(image,baos);
return baos.toByteArray();
} catch (Exception e) {
} finally {
if(baos != null)
try {
baos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return EMPTY_BYTES;
}
/**
* 自定义二维码白边宽度
* @param matrix
* @param margin
* @return
*/
private static BitMatrix updateBit(BitMatrix matrix,int margin) {
int tempM = margin * 2;
int[] rec = matrix.getEnclosingRectangle(); // 获取二维码图案的属性
int resWidth = rec[2] + tempM;
int resHeight = rec[3] + tempM;
BitMatrix resMatrix = new BitMatrix(resWidth,resHeight); // 按照自定义边框生成新的BitMatrix
resMatrix.clear();
for (int i = margin; i < resWidth - margin; i++) { // 循环,将二维码图案绘制到新的bitMatrix中
for (int j = margin; j < resHeight - margin; j++) {
if (matrix.get(i - margin + rec[0],j - margin + rec[1])) {
resMatrix.set(i,j);
}
}
}
return resMatrix;
}
// 图片放大缩小
public static BufferedImage zoomInImage(BufferedImage originalImage,int width,int height) {
BufferedImage newImage = new BufferedImage(width,originalImage.getType());
Graphics g = newImage.getGraphics();
g.drawImage(originalImage,width,null);
g.dispose();
return newImage;
}
private static void insertImage(BufferedImage source,Image insertImg,int size) {
try {
int width = insertImg.getWidth(null);
int height = insertImg.getHeight(null);
width = width > size / 6 ? size / 6 : width; // logo设为二维码的六分之一大小
height = height > size / 6 ? size / 6 : height;
Graphics2D graph = source.createGraphics();
int x = (size - width) / 2;
int y = (size - height) / 2;
graph.drawImage(insertImg,x,y,null);
Shape shape = new RoundRectangle2D.Float(x,6,6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] createQrCode(String content) {
return createQrCode(content,DEFAULT_QR_SIZE,DEFAULT_QR_FORMAT);
}
public static void main(String[] args){
try {
FileOutputStream fos = new FileOutputStream("ab.png");
fos.write(createQrCode("test"));
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
生成短链接 基本思路: 短网址映射算法的理论: 1.将长网址加随机数用用md5算法生成32位签名串,分为4段,每段8个字符 2.对这4段循环处理,取每段的8个字符,将他看成16进制字符串与0x3fffffff(30位1)的位与操作,超过30位的忽略处理 3.将每段得到的这30位又分成6段,每5位的数字作为字母表的索引取得特定字符,依次进行获得6位字符串; 4.这样一个md5字符串可以获得4个6位串,取里面的任意一个就可作为这个长url的短url地址。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
