Java qr code login process implementation code of includes short address generation including part of the code

  • 2020-05-19 04:46:55
  • OfStack

In recent years, the use of 2 d code is more and more popular, the author recently encountered a need to use 2 d code scan code login site live, so the study of 1 this 1 set of mechanisms, and the code to achieve the entire process, and we will talk about the 2 d code login and those things.

Principle of 2 d code

2 d code is WeChat up, when WeChat scan code 2 d code to log on to the web page WeChat, feel very magical, however, we understand its principle, also not so magical. The 2-d code is essentially a black and white bitmap containing an url request. Scan the code on the end, request url, do the corresponding operation.

Principle of general scanning operation

WeChat login, alipay scan code payment are the principle:

1. Request 2-d code

The desktop side initiates a request to the server for a 2-d code.

2. Generate a 2-dimensional code containing only 1id

The desktop will generate 1 id at random, and id only has 1 to identify this 2-dimensional code for subsequent operation.

3. Scan the code on the end

The mobile terminal scans the 2-d code to solve the request of url in the 2-d code of chu.

4. The mobile terminal sends a request to the server

The mobile terminal sends an url request to the server. The request contains two pieces of information, only 1id identifies which code it is scanning, and the specific cookie or header parameters in the browser on the terminal will identify which user is scanning the code.

5. The server side informs the code scanning to be successful

When the server receives the request of url for the information in the 2-d code, it will notify the server that the code has been scanned successfully and add the necessary login information such as Cookie. There are several methods of notification here: websocket, hold rotation training request until timeout, rotation training every few seconds.

The art of url in 2d code

How to implement the difference between the performance of your own client and that of other clients (such as WeChat)

For example, in the business, you may want to do this, if your company's 2d code is scanned by other app (such as WeChat), want to jump to a prompt page, the prompt page can have a download link of app; When scanned by your own app, make the request directly.

In this case, you can do this by encrypting all the links in the 2-d code at one layer and then processing them with another link.

Such as: www. test. com/qr & # 63; p = xxxxxx, p parameters contained in the server and the client agreement of encryption algorithm (can be symmetric asymmetric), on the scan code to this particular path directly with decryption algorithm p parameters, get www. testqr. com/qrcode & # 63; key = s1arV, so you can ask the server for the other client because don't know the rules, can only go directly to request www. test. com/qr & # 63; p=xxxxxx, this request returns to the prompt page.

How to make 2-d code easier

Most of the time, we want the horse to run, and we want the horse not to eat grass. You want a 2-d code with a lot of parameters, but you don't want the 2-d code to be too complex to scan out. At this point, you need to consider how to make the 2-d code simple without affecting the business.

With the convention rule on the end: for example, define the i parameter 1,2,3 in the encoding information to represent the different uri, and match the interface requested when different i parameters are encountered on the end Simplify 1 cut where you can simplify: simplify uri, simplify the parameters key, value. Such as www. a. com/q & # 63; k = s1arV than www. abc. def. adfg. edu. com. cn qrcode/scan & # 63; k = 77179574 e98a7c860007df62a5dbd98b to simplify a lot, generation of 2 d code is better a lot. Simplified only 1id parameter: the parameter value in the first request in the previous one is only 5 bits, and the parameter value in the second one is the generated 32-bit md5 value. It is critical to generate a 1-end key.

The sample code

Generate 2-d code (remove the white edge and add logo in the middle)

You need to import the jar package: core-2.0.jar of zxing


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);
  }

  /**
   *  Generate with pictures 2 D code 
   * @param content 2 The information to be included in a dimension code 
   * @param size  The size of the 
   * @param extension  File format extension 
   * @param insertImg  In the middle of the logo The picture 
   * @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 the information to generate a lattice of specified size 
      BitMatrix m = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, size, size, hints);
      
      // Remove the white border 
      m = updateBit(m, 0);
      
      int width = m.getWidth();
      int height = m.getHeight();
      
      // will BitMatrix The information set to BufferdImage In, form a black and white picture 
      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) {
        //  interposed logo The picture 
        insertImage(image, insertImg, m.getWidth());
      }
      // Zoom in on a picture that has been made smaller by removing 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;
  }
  
  /**
   *  The custom 2 Dimension 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(); //  To obtain 2 Attributes of a dimensional pattern 
    int resWidth = rec[2] + tempM;
    int resHeight = rec[3] + tempM;
    BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); //  Generate new by custom border BitMatrix
    resMatrix.clear();
    for (int i = margin; i < resWidth - margin; i++) { //  Cycle, 2 Dimension code pattern drawn to the new bitMatrix In the 
      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;
  }
  
  //  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; // logo Set to 2 D yards 6 m 1 The size of the 
      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 idea:

Theory of short url mapping algorithm:

1. The long url plus random number is generated by md5 algorithm with 32-bit signature string, which is divided into 4 segments with 8 characters in each segment

2. Take 8 characters of each segment and treat it as hexadecimal string and the bit and operation of 0x3fffffff(30-bit 1). Ignore the processing of more than 30 bits

3. Divide the 30 bits obtained from each paragraph into 6 segments, and obtain specific characters for each 5-bit digit as the index of the alphabet, and obtain the 6-bit string in turn;

4. Thus, one md5 string can obtain four six-bit strings, and any one of them can be used as the short url address of the long url.

5. It is better to use 1 key-value database for storage, and replace it with 1 when 10000 collision occurs. If all 4 collide, md5 will be generated again (because of the random number, different md5 will be generated).


public class ShortUrlUtil {

  /**
   *  The incoming 32 position md5 value 
   * @param md5
   * @return
   */
  public static String[] shortUrl(String md5) {
    //  To use generate  URL  The character of 
    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++) {

      //  Put the encrypted characters as follows  8  position 1 group  16  Into the system and  0x3FFFFFFF  Carry out bit and operation, over 30 Who ignore 
      String sTempSubString = md5.substring(i * 8, i * 8 + 8);

      //  We need to use  long  Type to convert because  Inteper .parseInt()  Can only handle  31  position  ,  The first place is the sign bit  ,  If it's not  long  , will cross the line 
      long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
      String outChars = "";
      for (int j = 0; j < 6; j++) {
        //  You take the values that you get  0x0000003D  Bit and operation, get the array of characters  chars  The index 
        long index = 0x0000003D & lHexLong;
        //  Add the obtained characters 
        outChars += chars[(int) index];
        //  Move bit to right for each cycle  5  position 
        lHexLong = lHexLong >> 5;
      }
      //  Puts 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);
    }
  }
  
}

Core code is not original, borrowed from others code, thank you!


Related articles: