一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|

服務器之家 - 編程語言 - JAVA教程 - Java二維碼登錄流程實現代碼(包含短地址生成,含部分代碼)

Java二維碼登錄流程實現代碼(包含短地址生成,含部分代碼)

2020-07-08 14:24白羊沈歌 JAVA教程

近年來,二維碼的使用越來越風生水起,本篇文章主要介紹了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,這個請求返回提示頁。

如何讓二維碼更簡單

很多時候,又要馬兒跑,又要馬兒不吃草。想要二維碼中帶有很多參數,但是又不想要二維碼太復雜,難以被掃碼出來。這時候,就需要考慮如何在不影響業務的情況下讓二維碼變的簡單。

  • 與端上約定規則:比如定義編碼信息中i參數為1,2,3表示不同的uri,端上來匹配遇到不同的i參數時請求哪個接口
  • 簡化一切能簡化的地方:簡化uri,簡化參數中的key、value。如www.a.com/q?k=s1arV就比www.abc.def.adfg.edu.com.cn/qrcode/scan?k=77179574e98a7c860007df62a5dbd98b 要簡化很多,生成的二維碼要好掃很多。
  • 簡化唯一id參數:上一條中前一個請求中參數值只有5位,后一個請求中參數值為生成的32位md5值。生成一個端的key至關重要。

示例代碼

生成二維碼(去掉白邊,增加中間的logo)

需要導入jar包:zxing的 core-2.0.jar

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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();
    }
    
  }
  
}

生成短鏈接

基本思路:

短網址映射算法的理論:

1.將長網址加隨機數用用md5算法生成32位簽名串,分為4段,每段8個字符

2.對這4段循環處理,取每段的8個字符, 將他看成16進制字符串與0x3fffffff(30位1)的位與操作,超過30位的忽略處理

3.將每段得到的這30位又分成6段,每5位的數字作為字母表的索引取得特定字符,依次進行獲得6位字符串;

4.這樣一個md5字符串可以獲得4個6位串,取里面的任意一個就可作為這個長url的短url地址。

5.最好是用一個key-value數據庫存儲,萬一發生碰撞換一個,如果四個都發生碰撞,重新生成md5(因為有隨機數,會生成不一樣的md5)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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);
    }
  }
  
}

說明:核心代碼非原創,借鑒了他人的代碼,感謝!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/shenpengyan/p/6120257.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩一区国产二区欧美三 | 娇喘嗯嗯 轻点啊视频福利 九九九九在线精品免费视频 | 欧美高清乌克兰精品另类 | 3d欧美人禽交 | 欧美草逼视频 | 99热精品69堂国产 | 999精品视频在线观看热6 | 国产精品反差婊在线观看 | 四虎在线免费 | freesex 18 19处xx| 国模丰满美女冰漪34d | 精品国产欧美一区二区五十路 | 91手机在线 | 亚洲爱视频 | 久久受www免费人成_看片中文 | 8x8拨擦拨擦华人免费 | 描写细腻的高h肉 | 天天操精品 | 精品9e精品视频在线观看 | 都市风流贵妇激情 | 亚洲性色永久网址 | 99r8这里精品热视频免费看 | 双性np玩烂了np欲之国的太子 | 欧美添下面视频免费观看 | 91欧美秘密入口 | 亚洲免费在线观看 | 男女激情视频1000辣妞范 | 我年轻漂亮的继坶2中字在线播放 | 秋霞午夜视频 | 国产精品久久久久久久久99热 | 草莓香蕉绿巨人丝瓜榴莲污在线观看 | 国产欧美一区二区三区免费 | 精品一二三区久久AAA片 | 久久亚洲国产成人影院 | 国产精品夜夜爽张柏芝 | 91夜色视频 | 男人机机桶女人机机 | 国产私拍精品88福利视频 | 疯狂伦交1一6小说 | 人禽l交免费视频观看+视频 | 99精品热线在线观看免费视频 |