In recent years, the use of QR codes has become more and more prosperous. Recently, I have encountered a job that requires scanning the QR code to log in to the website. So I have studied this mechanism and implemented the entire process with the code. Next, I will talk to you about the QR code login and other things.
The principle of QR code
The QR code was created by WeChat. When we scan the QR code on WeChat, we felt very magical when we logged into the webpage of WeChat. However, after we understand its principles, it is not that magical. The QR code actually contains a url request information through a black and white dot matrix. Scan the code on the terminal, request the url, and do the corresponding operation.
The principle of general code scanning operation
This is the principle of WeChat login and Alipay scanning code payment:
1. Request a QR code
The desktop initiates a QR code request to the server.
2. Generate a QR code with a unique id
The desktop will randomly generate an id, and the id will uniquely identify this QR code for subsequent operations.
3. Scan the code on the board
Scan the QR code on the mobile terminal to solve the URL request in the QR code.
4. The mobile terminal sends a request to the server
The mobile terminal sends a url request to the server, which contains two information. The unique id identifies which code is scanned, and the specific cookie or header parameters in the browser on the terminal will identify which user to scan the code.
5. Server-side notification to scan the code successfully
When the server receives the URL request for the information in the QR code, the notification side has successfully scanned the code and added necessary login cookies and other information. There are generally several notification methods here: websocket, training hold request until timeout, and training takes several seconds.
The art of url in QR code
How to realize the difference between scanning codes (such as WeChat) between your own client and other client
For example, in business, you may want to do this. If your company's QR code is scanned by other apps (such as WeChat), and you want to jump to a prompt page, there can be an app download link on the prompt page; and when it is scanned by your own app, make the corresponding request directly.
In this case, this can be done, all links in the QR code are encrypted in one layer, and then handled with another link.
For example: www.test.com/qr?p=xxxxxx, the p parameter contains the encryption and decryption algorithm agreed by the server and the client (can be symmetrical or asymmetrical). When scanning the code on the terminal to this specific path, the p parameter is directly used to solve the p parameter and get www.testqr.com/qrcode?key=s1arV, so that the request can be initiated to the server. Because other clients do not know this rule, they can only directly request www.test.com/qr?p=xxxxxx. This request returns to the prompt page.
How to make QR code simpler
Many times, the horses are asked to run and not eat grass. I want the QR code to have many parameters, but I don’t want the QR code to be too complicated and it is difficult to scan the code. At this time, you need to consider how to make the QR code simple without affecting the business.
Sample code
Generate QR code (remove the white edges and add the middle logo)
Need to import the jar package: 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 final byte[] EMPTY_BYTES = new byte[0]; public static byte[] createQrCode(String content, int size, String extension) { return createQrCode(content, size, extension, null); } /** * Generate a QR code with an image* @param content Information to be included in the QR code* @param size Size* @param extension File format extension* @param insertImg The middle logo image* @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); //Use information to generate a dot matrix of specified size BitMatrix m = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, size, size, hints); //Remove white edge m = updateBit(m, 0); int width = m.getWidth(); int height = m.getHeight(); //Set the information in BitMatrix into the BufferdImage to form a black and white image 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) { // Insert the middle logo image insertImage(image, insertImg, m.getWidth()); } // Enlarge the image that has become smaller due to the removal of the white edge 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; } /** * Custom QR code white edge width* @param matrix * @param margin * @return */ private static BitMatrix updateBit(BitMatrix matrix, int margin) { int tempM = margin * 2; int[] rec = matrix.getEnclosingRectangle(); // Get the attribute of the QR code pattern int resWidth = rec[2] + tempM; int resHeight = rec[3] + tempM; BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); // Generate new BitMatrix resMatrix.clear() according to the custom border; for (int i = margin; i < resWidth - margin; i++) { // Loop to draw the QR code pattern into the new 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; } // Image zoom in and out 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; // Set the logo to one-sixth of the size of the QR code 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(); } } }Generate short links
Basic ideas:
The theory of short URL mapping algorithm:
1. Use the md5 algorithm to generate a 32-bit signature string, divided into 4 segments, each segment with 8 characters.
2. For these 4 segments, take 8 characters in each segment, treat it as a bit and operation of hexadecimal string and 0x3ffffffff (30 bit 1), and ignore the processing of more than 30 bits.
3. Divide the 30 digits obtained in each segment into 6 segments, and obtain specific characters as the index of the alphabet, and obtain 6-bit strings in turn;
4. Such an md5 string can obtain 4 6-bit strings, and any of them can be used as the short URL address of this long URL.
5. It is best to use a key-value database to store it. In case of collision, replace one. If all four collide, regenerate md5 (because there are random numbers, different md5 will be generated)
public class ShortUrlUtil { /** * Pass in 32-bit md5 value* @param md5 * @return */ public static String[] shortUrl(String md5) { // To use the character that generates the 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", "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++) { // Put the encrypted characters as 8 Bits are a set of hexadecimal and 0x3FFFFFFFFFFFF and perform bit and calculations. If more than 30 bits are ignored String sTempSubString = md5.substring(i * 8, i * 8 + 8); // You need to use the long type to convert here, because Inteper .parseInt() can only process 31 bits, and the first bit is the sign bit. If you do not use long, it will be out of bounds long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16); String outChars = ""; for (int j = 0; j < 6; j++) { // Make the obtained value with 0x000003D Perform bit and operation to obtain the character array chars index long index = 0x0000003D & lHexLong; // Add the obtained characters outChars += chars[(int) index]; // Each loop is bit-right shifted by 5 bits lHexLong = lHexLong >> 5; } // Save the string into the output array of the corresponding index resUrl[i] = outChars; } return resUrl; } public static void main(String [] args){ String[] test = shortUrl("fdf8d941f23680be79af83f921b107ac"); for (String string : test) { System.out.println(string); } } } Note: The core code is not original and borrows from other people's code, thank you!
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.