Ces dernières années, l'utilisation de codes QR est devenue de plus en plus populaire. L'auteur a récemment rencontré un travail qui nécessitait de scanner des codes QR pour se connecter au site Web, j'ai donc étudié ce mécanisme et l'ai implémenté avec du code. tout au long du processus, parlons de la connexion par code QR et d'autres choses.
Principe du code QR
Le code QR a été créé par WeChat. Lorsque WeChat a scanné le code QR pour se connecter à la page Web WeChat, cela nous a semblé incroyable. Cependant, nous comprenons son principe, ce n'est pas le cas. c'est plus magique. Le code QR contient en fait des informations de demande d'URL via une matrice de points noir et blanc. Scannez le code sur le terminal, demandez l'URL et effectuez l'opération correspondante.
Le principe des opérations générales de numérisation de code
La connexion WeChat et le paiement par scanner Alipay sont tous basés sur ce principe :
Demander un code QR
1.Le côté bureau lance une demande de code QR auprès du serveur.
2. Générez un code QR contenant un identifiant unique
Le bureau générera aléatoirement un identifiant, qui identifie de manière unique le code QR pour les opérations ultérieures.
3. Scannez le code QR sur le terminal mobile
Scannez le code QR sur le terminal mobile et décodez la demande d'url dans le code QR.
4. Le terminal mobile envoie une requête au serveur
Le terminal mobile envoie une requête URL au serveur La requête contient deux informations. , et le code spécifique dans le navigateur du terminal. Les paramètres du cookie ou de l'en-tête identifieront quel utilisateur a scanné le code.
5. Le serveur informe que l'analyse du code est réussie
Lorsque le serveur reçoit la demande URL pour les informations contenues dans le code QR, il informe le serveur que l'analyse du code a réussi et ajoute les cookies de connexion nécessaires et d’autres informations. Il existe généralement plusieurs méthodes de notification ici : websocket, interrogation, maintien de la demande jusqu'à l'expiration du délai et interrogation toutes les quelques secondes.
L'art de l'url dans le code QR
Comment réaliser les différentes performances de numérisation de code entre votre propre client et d'autres clients (comme WeChat)
Par exemple, dans entreprise, vous souhaiterez peut-être le faire. Si le code QR de votre entreprise est scanné par d'autres applications (telles que WeChat) et que vous souhaitez accéder à une page d'invite, il peut y avoir un lien de téléchargement pour l'application sur la page d'invite et à quel moment ; il est scanné par vous-même. Lors du scan par l'application, la demande correspondante est faite directement.
Dans ce cas, vous pouvez procéder de cette façon. Tous les liens dans le code QR sont cryptés puis traités uniformément avec un autre lien.
Par exemple : www.test.com/qr?p=xxxxxx, le paramètre p contient l'algorithme de cryptage et de déchiffrement convenu entre le serveur et le client (peut être symétrique ou asymétrique), scannez le code sur le end to Lorsque vous utilisez ce chemin spécifique, utilisez directement l'algorithme de décryptage pour décoder le paramètre p et obtenir www.testqr.com/qrcode?key=s1arV De cette manière, une requête peut être adressée au serveur Cependant, car d'autres clients. Je ne connais pas cette règle, ils ne peuvent que directement Aller à la demande www.test.com/qr?p=xxxxxx, cette demande renvoie la page d'invite.
Comment simplifier les codes QR
Souvent, nous devons faire courir un cheval et un cheval ne pas manger d'herbe. Vous souhaitez que le code QR contienne de nombreux paramètres, mais vous ne voulez pas que le code QR soit trop compliqué et difficile à scanner. À l’heure actuelle, vous devez réfléchir à la manière de simplifier le code QR sans affecter l’entreprise.
Acceptez les règles de fin : par exemple, définissez le paramètre i dans les informations d'encodage comme 1, 2, 3 pour représenter différents URI, et la fin correspondra à l'interface à demander lorsque vous rencontrez différents paramètres i.
Simplifié Tout ce qui peut être simplifié : simplifier l'uri, simplifier la clé et la valeur dans les paramètres. Par exemple, www.a.com/q?k=s1arV est beaucoup plus simple que www.abc.def.adfg.edu.com.cn/qrcode/scan?k=77179574e98a7c860007df62a5dbd98b, et le code QR généré est beaucoup plus facile à scanner. .
Simplifiez le paramètre d'identification unique : dans l'article précédent, la valeur du paramètre dans la requête précédente n'est que de 5 chiffres, et la valeur du paramètre dans cette dernière requête est la valeur md5 32 bits générée. La génération d’une clé de terminal est cruciale.
Exemple de code
Générer un code QR (supprimez la bordure blanche et ajoutez le logo au milieu)
Besoin d'importer le package jar : 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(); } } }
Générer des liens courts
Idée de base :
La théorie de l'algorithme de mappage d'URL courtes :
1. Ajoutez des URL longues à des nombres aléatoires et utilisez-les. l'algorithme md5 pour générer une chaîne de signature de 32 chiffres, divisée en 4 segments, chaque segment comporte 8 caractères
2. Traitez ces 4 segments en boucle, prenez les 8 caractères de chaque segment, et traitez-le comme un hexadécimal chaîne avec 0x3fffffff (30 bits ET opération du bit 1), plus de 30 bits sont ignorés
3 Divisez les 30 bits obtenus dans chaque segment en 6 segments, et chaque nombre à 5 chiffres est utilisé comme index. de l'alphabet pour obtenir des caractères spécifiques, dans l'ordre Obtenir une chaîne à 6 chiffres ;
4. Une telle chaîne md5 peut obtenir quatre chaînes à 6 chiffres, et chacune d'entre elles peut être utilisée comme adresse URL courte. de cette longue URL.
5. Il est préférable d'utiliser une base de données clé-valeur pour le stockage. En cas de collision, remplacez-la par une autre. Si les quatre entrent en collision, régénérez md5 (car il y a des nombres aléatoires, différents md5 seront générés. )
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); } } }
Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'apprentissage de chacun. J'espère également que tout le monde soutiendra le site Web PHP chinois.
Pour plus d'articles sur le code de mise en œuvre du processus de connexion au code QR Java (y compris la génération d'adresses courtes, y compris certains codes), veuillez faire attention au site Web PHP chinois !