亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2016年12月01日 08:27:22   作者:白羊沈歌  
近年來,二維碼的使用越來越風(fēng)生水起,本篇文章主要介紹了Java二維碼登錄流程實(shí)現(xiàn)代碼,其中包含短地址生成,有興趣的可以了解一下。

近年來,二維碼的使用越來越風(fēng)生水起,筆者最近手頭也遇到了一個(gè)需要使用二維碼掃碼登錄網(wǎng)站的活,所以研究了一下這一套機(jī)制,并用代碼實(shí)現(xiàn)了整個(gè)流程,接下來就和大家聊聊二維碼登錄及的那些事兒。

二維碼原理

二維碼是微信搞起來的,當(dāng)年微信掃碼二維碼登錄網(wǎng)頁(yè)微信的時(shí)候,感覺很神奇,然而,我們了解了它的原理,也就沒那么神奇了。二維碼實(shí)際上就是通過黑白的點(diǎn)陣包含了一個(gè)url請(qǐng)求信息。端上掃碼,請(qǐng)求url,做對(duì)應(yīng)的操作。

一般性掃碼操作的原理

微信登錄、支付寶掃碼支付都是這個(gè)原理:

1. 請(qǐng)求二維碼

桌面端向服務(wù)器發(fā)起請(qǐng)求一個(gè)二維碼的。

2. 生成包含唯一id的二維碼

桌面端會(huì)隨機(jī)生成一個(gè)id,id唯一標(biāo)識(shí)這個(gè)二維碼,以便后續(xù)操作。

3. 端上掃碼

移動(dòng)端掃碼二維碼,解chu出二維碼中的url請(qǐng)求。

4. 移動(dòng)端發(fā)送請(qǐng)求到服務(wù)器

移動(dòng)端向服務(wù)器發(fā)送url請(qǐng)求,請(qǐng)求中包含兩個(gè)信息,唯一id標(biāo)識(shí)掃的是哪個(gè)碼,端上瀏覽器中特定的cookie或者h(yuǎn)eader參數(shù)等會(huì)標(biāo)識(shí)由哪個(gè)用戶來進(jìn)行掃碼的。

5. 服務(wù)器端通知掃碼成功

服務(wù)器端收到二維碼中信息的url請(qǐng)求時(shí),通知端上已經(jīng)掃碼成功,并添加必要的登錄Cookie等信息。這里的通知方式一般有幾種:websocket、輪訓(xùn)hold住請(qǐng)求直到超時(shí)、隔幾秒輪訓(xùn)。

二維碼中url的藝術(shù)

如何實(shí)現(xiàn)自有客戶端和其他客戶端掃碼(如微信)表現(xiàn)的不同

比如,在業(yè)務(wù)中,你可能想要這樣的操作,如果是你公司的二維碼被其他app(如微信)所掃描,想要跳轉(zhuǎn)一個(gè)提示頁(yè),提示頁(yè)上可以有一個(gè)app的下載鏈接;而當(dāng)被你自己的app所掃描時(shí),直接進(jìn)行對(duì)應(yīng)的請(qǐng)求。

這種情況下,可以這樣來做,所有二維碼中的鏈接都進(jìn)行一層加密,然后統(tǒng)一用另一個(gè)鏈接來處理。

如:www.test.com/qr?p=xxxxxx,p參數(shù)中包含服務(wù)器與客戶端約定的加解密算法(可以是對(duì)稱的也可以是非對(duì)稱的),端上掃碼到這種特定路徑的時(shí)候,直接用解密算法解p參數(shù),得到www.testqr.com/qrcode?key=s1arV,這樣就可以向服務(wù)器發(fā)起請(qǐng)求了,而其他客戶端因?yàn)椴恢肋@個(gè)規(guī)則,只能直接去請(qǐng)求www.test.com/qr?p=xxxxxx,這個(gè)請(qǐng)求返回提示頁(yè)。

如何讓二維碼更簡(jiǎn)單

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

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

示例代碼

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

需要導(dǎo)入jar包:zxing的 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 文件格式擴(kuò)展
   * @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);

      //使用信息生成指定大小的點(diǎn)陣
      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中的信息設(shè)置到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());
      }
      //將因?yàn)槿グ走叾冃〉膱D片再放大
      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++) { // 循環(huán),將二維碼圖案繪制到新的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設(shè)為二維碼的六分之一大小
      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();
    }
    
  }
  
}

生成短鏈接

基本思路:

短網(wǎng)址映射算法的理論:

1.將長(zhǎng)網(wǎng)址加隨機(jī)數(shù)用用md5算法生成32位簽名串,分為4段,每段8個(gè)字符

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

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

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

5.最好是用一個(gè)key-value數(shù)據(jù)庫(kù)存儲(chǔ),萬一發(fā)生碰撞換一個(gè),如果四個(gè)都發(fā)生碰撞,重新生成md5(因?yàn)橛须S機(jī)數(shù),會(huì)生成不一樣的md5)

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 進(jìn)制與 0x3FFFFFFF 進(jìn)行位與運(yùn)算,超過30位的忽略
      String sTempSubString = md5.substring(i * 8, i * 8 + 8);

      // 這里需要使用 long 型來轉(zhuǎn)換,因?yàn)?Inteper .parseInt() 只能處理 31 位 , 首位為符號(hào)位 , 如果不用 long ,則會(huì)越界
      long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
      String outChars = "";
      for (int j = 0; j < 6; j++) {
        // 把得到的值與 0x0000003D 進(jìn)行位與運(yùn)算,取得字符數(shù)組 chars 索引
        long index = 0x0000003D & lHexLong;
        // 把取得的字符相加
        outChars += chars[(int) index];
        // 每次循環(huán)按位右移 5 位
        lHexLong = lHexLong >> 5;
      }
      // 把字符串存入對(duì)應(yīng)索引的輸出數(shù)組
      resUrl[i] = outChars;
    }
    return resUrl;
  }
  
  public static void main(String [] args){
    String[] test = shortUrl("fdf8d941f23680be79af83f921b107ac");
    for (String string : test) {
      System.out.println(string);
    }
  }
  
}

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

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL更新的代碼示例

    MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL更新的代碼示例

    本文博小編將帶領(lǐng)大家學(xué)習(xí)如何利用 MyBatis 攔截器機(jī)制來優(yōu)雅的實(shí)現(xiàn)這個(gè)需求,文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 加速spring/springboot應(yīng)用啟動(dòng)速度詳解

    加速spring/springboot應(yīng)用啟動(dòng)速度詳解

    這篇文章主要介紹了加速spring/springboot應(yīng)用啟動(dòng)速度詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a

    java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a

    這篇文章主要介紹了java 簡(jiǎn)單的計(jì)算器程序?qū)嵗a的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java8中Stream流求最大值最小值的實(shí)現(xiàn)示例

    Java8中Stream流求最大值最小值的實(shí)現(xiàn)示例

    本文主要介紹了Java8中Stream流求最大值最小值的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • java枚舉的使用示例

    java枚舉的使用示例

    我們?cè)趯W(xué)習(xí)編程語言的時(shí)候都學(xué)過枚舉,現(xiàn)在就具體來看看java中的枚舉的使用
    2013-12-12
  • Java讀取.properties配置文件方法示例

    Java讀取.properties配置文件方法示例

    這篇文章主要介紹了Java讀取.properties配置文件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 友盟 微信第三方登錄示例

    友盟 微信第三方登錄示例

    這篇文章主要介紹了友盟 微信第三方登錄示例的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Java?多線程并發(fā)編程提高數(shù)據(jù)處理效率的詳細(xì)過程

    Java?多線程并發(fā)編程提高數(shù)據(jù)處理效率的詳細(xì)過程

    這篇文章主要介紹了Java?多線程并發(fā)編程提高數(shù)據(jù)處理效率,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之線上水果超市商城的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之線上水果超市商城的實(shí)現(xiàn)

    這是一個(gè)使用了java+SSM+springboot+redis開發(fā)的網(wǎng)上水果超市商城,是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有水果超市商城該有的所有功能,感興趣的朋友快來看看吧
    2022-01-01
  • Java如何重寫object類的equals方法詳解

    Java如何重寫object類的equals方法詳解

    這篇文章主要給大家介紹了關(guān)于Java如何重寫object類的equals方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論