Java emoji持久化mysql過程詳解
前言
好久沒有更新博客了,今天和大家分享一個關于emoji表情持久化問題,相信做web開發(fā)的都遇到過這樣的問題,因為我們知道m(xù)ysql的utf-8字符集保存不了保存不了表情字符,這是為什么呢?因為普通的字符串或者表情都是占位3個字節(jié),所以utf8足夠用了,但是移動端的表情符號占位是4個字節(jié),普通的utf8就不夠用了,為了應對無線互聯(lián)網(wǎng)的機遇和挑戰(zhàn)、避免 emoji 表情符號帶來的問題、涉及無線相關的 MySQL 數(shù)據(jù)庫建議都提前采用 utf8mb4 字符集,這必須要作為移動互聯(lián)網(wǎng)行業(yè)的一個技術選型的要點。
好了看到上面的結果你是不是已經(jīng)去修改數(shù)據(jù)庫字符集了,如果你是個人項目或小項目上面的方法倒是一個解決方法,但是對于一個目前正在服務5000W用戶的系統(tǒng),上面的方式就有點不合適了,針對這種情況我這邊總結了三種處理方式,下面分享給大家:
1、既然是由于移動端的表情符號占位是4個字節(jié),那我們直接把數(shù)據(jù)轉換后保存。
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、有了上面兩種方式,你是不是已經(jīng)滿足了,最為自己最推崇的emoji處理方式,下面才是重點,首先說一下上面兩種方式存在的問題:第一種方式,數(shù)據(jù)經(jīng)過轉換,相當于加密,我們將無法直接查看到數(shù)據(jù)的原始內(nèi)容,由其對于需要進行搜索的業(yè)務場景,將是一件很困難的事情;第二種方式,雖然避免了第一種方式存在的問題,但是它基于表情的對照表進行匹配轉換的,也就意味著對于一些新表情,無法做到轉換,這就會導致我們數(shù)據(jù)插入繼續(xù)出現(xiàn)問題,這是它第一個問題,第二點在于它將表情轉化為對應的匹配規(guī)則,說白一點就是轉化為英文描述,就是這個轉化,原本4個字節(jié)的表情,它可能給你轉成了10個字節(jié)甚至更多。好了說了這么多下面我們看一下我最后的終極解決方法:
/**
* @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));
}
}
好了就先這樣,歡迎大家提出不同的看法,已經(jīng)好的解決方案。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Java解析zip文件,并識別壓縮包里面的文件轉換成可操作的IO流方式
這篇文章主要介紹了Java解析zip文件,并識別壓縮包里面的文件轉換成可操作的IO流方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
JAVA實現(xiàn)遍歷文件夾下的所有文件(遞歸調用和非遞歸調用)
本篇文章主要介紹了JAVA 遍歷文件夾下的所有文件(遞歸調用和非遞歸調用) ,具有一定的參考價值,有興趣的可以了解一下。2017-01-01
UrlDecoder和UrlEncoder使用詳解_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了UrlDecoder和UrlEncoder使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07

