In den letzten Jahren ist die Verwendung von QR-Codes immer beliebter geworden. Der Autor ist kürzlich auf einen Job gestoßen, der das Scannen von QR-Codes erfordert, um sich auf der Website anzumelden. Daher habe ich diesen Mechanismus untersucht und ihn mit Code implementiert Lassen Sie uns während des gesamten Prozesses mit Ihnen über die QR-Code-Anmeldung und andere Dinge sprechen.
Prinzip des QR-Codes
Der QR-Code wurde von WeChat erfunden, um sich auf der Webseite WeChat anzumelden. Wir verstehen jedoch sein Prinzip nicht mehr so magisch. Der QR-Code enthält tatsächlich eine URL-Anforderungsinformation durch eine schwarz-weiße Punktmatrix. Scannen Sie den Code am Terminal, fordern Sie die URL an und führen Sie den entsprechenden Vorgang aus.
Das Prinzip der allgemeinen Code-Scanvorgänge
WeChat-Anmeldung und Alipay-Scancode-Zahlung basieren alle auf diesem Prinzip:
1. QR-Code anfordern
Die Desktop-Seite initiiert eine Anfrage nach einem QR-Code vom Server.
2. Erzeugen Sie einen QR-Code mit einer eindeutigen ID.
Der Desktop generiert nach dem Zufallsprinzip eine ID, die den QR-Code für nachfolgende Vorgänge eindeutig identifiziert.
3. Scannen Sie den QR-Code auf dem mobilen Endgerät
Scannen Sie den QR-Code auf dem mobilen Endgerät und entschlüsseln Sie die URL-Anfrage im QR-Code.
Das mobile Endgerät sendet eine Anfrage an den Server
Das mobile Endgerät sendet eine URL-Anfrage an den Server. Die eindeutige ID identifiziert, welcher Code gescannt wurde und der spezifische Code im Browser auf dem Terminal. Die Cookie- oder Header-Parameter identifizieren, welcher Benutzer den Code gescannt hat.
5. Der Server benachrichtigt, dass der Code-Scan erfolgreich war.
Wenn der Server die URL-Anfrage für die Informationen im QR-Code empfängt, benachrichtigt er den Server, dass der Code-Scan erfolgreich war fügt notwendige Login-Cookies und andere Informationen hinzu. Hier gibt es im Allgemeinen mehrere Benachrichtigungsmethoden: Websocket, Polling, Halten der Anfrage bis zum Timeout und Polling alle paar Sekunden.
Die Kunst der URL im QR-Code
Wie Sie die unterschiedliche Leistung des Scannens von Code zwischen Ihrem eigenen Client und anderen Clients (wie WeChat) erkennen können
Zum Beispiel in Unternehmen: Möglicherweise möchten Sie dies tun, wenn der QR-Code Ihres Unternehmens von anderen Apps (z. B. WeChat) gescannt wird und Sie zu einer Eingabeaufforderungsseite springen möchten. Auf der Eingabeaufforderungsseite befindet sich möglicherweise ein Download-Link für die App Es wird von Ihnen selbst gescannt. Beim Scannen durch die App wird direkt die entsprechende Anfrage gestellt.
In diesem Fall können Sie es auf diese Weise tun. Alle Links im QR-Code werden verschlüsselt und dann einheitlich mit einem anderen Link verarbeitet.
Zum Beispiel: www.test.com/qr?p=xxxxxx, der p-Parameter enthält den zwischen dem Server und dem Client vereinbarten Verschlüsselungs- und Entschlüsselungsalgorithmus (kann symmetrisch oder asymmetrisch sein), scannen Sie den Code auf dem Ende zu Wenn Sie diesen spezifischen Pfad verwenden, verwenden Sie den Entschlüsselungsalgorithmus direkt, um den p-Parameter zu entschlüsseln und www.testqr.com/qrcode?key=s1arV zu erhalten. Auf diese Weise kann jedoch eine Anfrage an den Server gestellt werden Wenn Sie diese Regel nicht kennen, können Sie nur direkt zur Anfrage www.test.com/qr?p=xxxxxx gehen. Diese Anfrage gibt die Eingabeaufforderungsseite zurück.
Wie man QR-Codes einfacher macht
Oft müssen wir ein Pferd laufen lassen und ein Pferd dazu bringen, kein Gras zu fressen. Sie möchten, dass der QR-Code viele Parameter enthält, aber Sie möchten nicht, dass der QR-Code zu kompliziert und schwierig zu scannen ist. Zu diesem Zeitpunkt müssen Sie darüber nachdenken, wie Sie den QR-Code einfach gestalten können, ohne das Geschäft zu beeinträchtigen.
Stimmen Sie den Regeln am Ende zu: Definieren Sie beispielsweise den i-Parameter in den Codierungsinformationen als 1, 2, 3, um unterschiedliche URIs darzustellen, und am Ende wird festgelegt, welche Schnittstelle angefordert werden soll, wenn auf unterschiedliche i-Parameter gestoßen wird
Vereinfacht Alles, was vereinfacht werden kann: Vereinfachen Sie die URI, vereinfachen Sie den Schlüssel und den Wert in den Parametern. Beispielsweise ist www.a.com/q?k=s1arV viel einfacher als www.abc.def.adfg.edu.com.cn/qrcode/scan?k=77179574e98a7c860007df62a5dbd98b und der generierte QR-Code ist viel einfacher zu scannen .
Vereinfachen Sie den eindeutigen ID-Parameter: Im vorherigen Artikel besteht der Parameterwert in der vorherigen Anforderung nur aus 5 Ziffern, und der Parameterwert in der letzteren Anforderung ist der generierte 32-Bit-MD5-Wert. Die Generierung eines Terminalschlüssels ist von entscheidender Bedeutung.
Beispielcode
QR-Code generieren (den weißen Rand entfernen und das Logo in der Mitte hinzufügen)
Das JAR-Paket muss importiert werden: zxing's 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, int size, 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, size, size, 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, size); baos = new ByteArrayOutputStream(); ImageIO.write(image, extension, 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, height, originalImage.getType()); Graphics g = newImage.getGraphics(); g.drawImage(originalImage, 0, 0, width, height, 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, width, height, null); Shape shape = new RoundRectangle2D.Float(x, y, width, width, 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(); } } }
Kurzlinks generieren
Grundidee:
Theorie des Kurz-URL-Zuordnungsalgorithmus:
1. Verwenden Sie den MD5-Algorithmus, um 32 lange URLs zu generieren Zufallszahlen-Ziffernsignaturzeichenfolge, unterteilt in 4 Segmente, jedes Segment hat 8 Zeichen
2. Verarbeiten Sie diese 4 Segmente in einer Schleife, nehmen Sie die 8 Zeichen jedes Segments und behandeln Sie es als hexadezimale Zeichenfolge mit 0x3fffffff( 30-Bit-AND-Verknüpfung von Bit 1), mehr als 30 Bits werden ignoriert
3. Teilen Sie die in jedem Segment erhaltenen 30 Bits in 6 Segmente und jede 5-stellige Zahl wird als Index des Alphabets verwendet Erhalten Sie bestimmte Zeichen nacheinander. Erhalten Sie eine 6-stellige Zeichenfolge.
4 Eine solche MD5-Zeichenfolge kann vier 6-stellige Zeichenfolgen erhalten, und jede davon kann als kurze URL-Adresse dieser langen URL verwendet werden .
5. Es ist am besten, eine Schlüsselwertdatenbank zur Speicherung zu verwenden. Wenn alle vier kollidieren, generieren Sie MD5 neu (da es Zufallszahlen gibt, werden andere MD5 generiert )
public class ShortUrlUtil { /** * 传入32位md5值 * @param md5 * @return */ public static String[] shortUrl(String md5) { // 要使用生成 URL 的字符 String[] chars = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; String[] resUrl = new String[4]; for (int i = 0; i < 4; i++) { // 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算,超过30位的忽略 String sTempSubString = md5.substring(i * 8, i * 8 + 8); // 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界 long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16); String outChars = ""; for (int j = 0; j < 6; j++) { // 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引 long index = 0x0000003D & lHexLong; // 把取得的字符相加 outChars += chars[(int) index]; // 每次循环按位右移 5 位 lHexLong = lHexLong >> 5; } // 把字符串存入对应索引的输出数组 resUrl[i] = outChars; } return resUrl; } public static void main(String [] args){ String[] test = shortUrl("fdf8d941f23680be79af83f921b107ac"); for (String string : test) { System.out.println(string); } } }
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er zum Lernen aller beiträgt. Ich hoffe auch, dass jeder die PHP-Chinesisch-Website unterstützt.
Weitere Artikel zum Implementierungscode für den Java-QR-Code-Anmeldeprozess (einschließlich kurzer Adressgenerierung, einschließlich einiger Codes) finden Sie auf der chinesischen PHP-Website!