Java emoji持久化mysql

来源:https://www.cnblogs.com/AndroidJotting/archive/2019/07/26/11253202.html
-Advertisement-
Play Games

好久沒有更新博客了,今天和大家分享一個關於emoji表情持久化問題,相信做web開發的都遇到過這樣的問題,因為我們知道mysql的utf-8字元集保存不了保存不了表情字元,這是為什麼呢?因為普通的字元串或者表情都是占位3個位元組,所以utf8足夠用了,但是移動端的表情符號占位是4個位元組,普通的utf8 ...


  好久沒有更新博客了,今天和大家分享一個關於emoji表情持久化問題,相信做web開發的都遇到過這樣的問題,因為我們知道mysql的utf-8字元集保存不了保存不了表情字元,這是為什麼呢?因為普通的字元串或者表情都是占位3個位元組,所以utf8足夠用了,但是移動端的表情符號占位是4個位元組,普通的utf8就不夠用了,為了應對無線互聯網的機遇和挑戰、避免 emoji 表情符號帶來的問題、涉及無線相關的 MySQL 資料庫建議都提前採用 utf8mb4 字元集,這必須要作為移動互聯網行業的一個技術選型的要點。

  好了看到上面的結果你是不是已經去修改資料庫字元集了,如果你是個人項目或小項目上面的方法倒是一個解決方法,但是對於一個目前正在服務5000W用戶的系統,上面的方式就有點不合適了,針對這種情況我這邊總結了三種處理方式,下麵分享給大家:

  1、既然是由於移動端的表情符號占位是4個位元組,那我們直接把數據轉換後保存。

1.URLEncoder.encode(String s, String enc) 
使用指定的編碼機制將字元串轉換為 application/x-www-form-urlencoded 格式 

URLDecoder.decode(String s, String enc) 
使用指定的編碼機制對 application/x-www-form-urlencoded 字元串解碼。 

  2、方法一的處理太粗躁,有沒有更好的解決辦法呢?使用輕量級工具emoji-java處理emoji表情字元

github地址:https://github.com/vdurmont/emoji-java

  具體使用方式,大家可以進入git中自行查看。

  3、有了上面兩種方式,你是不是已經滿足了,最為自己最推崇的emoji處理方式,下麵才是重點,首先說一下上面兩種方式存在的問題:第一種方式,數據經過轉換,相當於加密,我們將無法直接查看到數據的原始內容,由其對於需要進行搜索的業務場景,將是一件很困難的事情;第二種方式,雖然避免了第一種方式存在的問題,但是它基於表情的對照表進行匹配轉換的,也就意味著對於一些新表情,無法做到轉換,這就會導致我們數據插入繼續出現問題,這是它第一個問題,第二點在於它將表情轉化為對應的匹配規則,說白一點就是轉化為英文描述,就是這個轉化,原本4個位元組的表情,它可能給你轉成了10個位元組甚至更多。好了說了這麼多下麵我們看一下我最後的終極解決方法:

/**
 * @Author: gaoshang
 * @Description:
 * @Date: 2019/7/19
 */
public class EmojiUtil {

    /**
     * 將文本中的表情轉為十六進位
     * <p>
     *
     * @param input
     * @return
     */
    public static String parseFromAliases(String input) {
        if (input == null) {
            return input;
        }

        return stringToUnicode(input);
    }

    /**
     * 將文本中的十六進位轉為表情
     * <p>
     *
     * @param input
     * @return
     */
    public static String parseToAliases(String input) {
        if (input == null) {
            return input;
        }

        return unicodeToString(input);
    }

    /**
     * 字元串轉unicode
     *
     * @param str
     * @return
     */
    public static String stringToUnicode(String str) {
        StringBuilder sb = new StringBuilder();
        StringBuilder cacheSB = new StringBuilder();
        char[] c = str.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (!isEmojiCharacter(c[i])) {
                if (cacheSB.length() > 0) {
                    sb.append("\\u").append(cacheSB);
                    cacheSB.delete(0, cacheSB.length());
                }

                sb.append("\\u").append("[").append(Integer.toHexString(c[i])).append("]");
            } else {
                if (c[i] == '[' || c[i] == '\\' || c[i] == ']') {
                    if (cacheSB.length() > 0) {
                        sb.append("\\u").append(cacheSB);
                        cacheSB.delete(0, cacheSB.length());
                    }
                    sb.append("\\u").append(c[i]);
                } else {
                    cacheSB.append(c[i]);
                }
            }
        }
        if (cacheSB.length() > 0) {
            if (sb.length() > 0) {
                sb.append("\\u");
            }
            sb.append(cacheSB);
        }
        return sb.toString();
    }

    /**
     * unicode轉字元串
     *
     * @param unicode
     * @return
     */
    public static String unicodeToString(String unicode) {
        StringBuilder sb = new StringBuilder();
        String[] hex = unicode.split("\\\\u");
        for (int i = 0; i < hex.length; i++) {
            if (hex[i].indexOf("[") == 0 && hex[i].indexOf("]") == hex[i].length() - 1) {
                try {
                    int index = Integer.parseInt(hex[i].substring(1, hex[i].length() - 1), 16);
                    sb.append((char) index);
                } catch (NumberFormatException e) {
                    sb.append(hex[i]);
                }
            } else {
                sb.append(hex[i]);
            }
        }
        return sb.toString();
    }

    private static boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
                || (codePoint == 0xD)
                || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
                || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
                || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

}

  好了就先這樣,歡迎大家提出不同的看法,已經好的解決方案。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 先說顏色: 綠色:public 黃色:protected 藍色:no modifier 紅色:private 再說形狀: 實心:method 空心:variable 實心中間有字母C:class Class右側有向右的箭頭:運行入口 再說字母: S:static F:final 常用組合: 綠圓圈: ...
  • 基本思想 通過Dlib獲得當前人臉的特征點,然後通過旋轉平移標準模型的特征點進行擬合,計算標準模型求得的特征點與Dlib獲得的特征點之間的差,使用Ceres不斷迭代優化,最終得到最佳的旋轉和平移參數。 使用環境 系統環境:Ubuntu 18.04 使用語言:C++ 編譯工具:CMake 第三方工具 ...
  • 第一次打開PyCharm可能需要修改一些個性化和瞭解一些基本操作,有助於接下來的學習過程.(後續可能會更新) 我的版本是64位的1.3 1.換界麵皮膚 預設黑色的,不喜歡黑色皮膚可以換成白色的 File Settings Appearance&Behavior Appearance Theme 2. ...
  • 肯定有這樣的一種場景,寫一個函數,該函數可以接收任意類型的切片,完成相應的功能。 就好比這種情況 還有很多類型的切片,但是我對這些切片的使用,只是for迴圈每一個元素,執行Print操作就可以了。 那就定義一個函數,函數的接收參數就是這個切片就行了,但是切片類型太多了,你要根據不同的切片類型,寫不同 ...
  • 什麼是埃及乘法 埃及乘法的思路是:反覆地將n減半,並將a加倍,同時求出a的各種倍數,這些倍數與a的比值都是2的整數次冪。n的值為奇數部分的a之和即為所求值 舉個慄子:41 x 59 1 41 59 √ 2 20 118 4 10 236 8 5 472 √ 16 2 944 32 1 1888 √ ...
  • 運行結果: 發現乘法表有錯位,在程式中加入製表符,就解決了 程式如下: 運行結果: ...
  • 自定義註解開發 1.開發一個註解類 開發一個註解類的過程,非常類似於開發一個介面,只不過需要通過@interface關鍵字來聲明 2.使用元註解修飾註解的聲明 所謂的原註解是用來修飾註解聲明的註釋,可以控制被修飾的註解的特性。 @Target 用來聲明被修飾的註解可以用在什麼位置。 可以在@Targ ...
  • 一、簡介  Spring Cloud Confg 是用來為分散式系統中的基礎設施和微服務應用提供集中化的外部配置支持,它分為服務端與客戶端兩個部分。其中服務端也稱為分散式配置中心,它是一個獨立的微服務應用,用來連接配置倉庫併為客戶端提供獲取配置信息、加密/解密信息等訪問介面;而客戶端則是微 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...