一个emoji表情包处理工具类

article/2025/5/15 8:50:47

一个emoji表情包处理工具类

  • 参考
  • 业务场景
  • 解决方案
    • 方案一(mysql字符集)
    • 方案二(emoji表情包转码)

尊重他人成果、转载请注明出处

参考

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

业务场景

在常规如APP推送、BBS、论坛等类型的业务系统中,消息内容中包含emoji表情包(😁、💣、🦢)由于其本身的趣味性,在消息内容中引入的场景越来越普遍。
但是我们发现,若果直接存储emoji表情包,数据库通常会直接报如下异常:

Caused by: java.sql.SQLException: Incorrect string value: ‘\xF6\x8D\x78\x84’ for column ‘comment’ at row 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2734)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)

这是因为本身并不是直接支持emoji表情包,需要通过配置字符编码方式或者其它方案才能实现emoji包存储。
目前业界有两种解决方案:一、配置mysql字符集成utf8mb4;二、对emoji表情包进行转码存储。
两种方案各有优势吧,utf8mb4方案对数据库版本有要求,仅需修改配置,无需修改代码。从根源上解决emoji表情包存储问题。emoji表情包转码方案则对数据库版本没啥要求,但是需要对表情包内容进行编码、解码操作,因此对代码侵入性高。
这两种方案根据业务场景取舍吧。

解决方案

方案一(mysql字符集)

mysql5.5版本之前,数据库中的utf-8编码只支持1~3个字节(注:数据库中的utf-8并非广义上讲的utf-8,仅是utf-8的精简版本)。从mysql5.5开始支持4个字节的utf8mb4。
emoji表情包占用4个字节,因此要求mysql支持emoji表情包,则需要配置utf8mb4编码方式。目前网上有相当丰富的资源介绍,因此本文仅简单介绍。

查看mysql当前的编码方式:

show variables like ‘%character%’;

在这里插入图片描述

方案二(emoji表情包转码)

针对已经成熟的线上系统或者mysql版本较老,基于数据安全及系统稳定性考虑,建议采用emoji表情包转码方案,无需修改线上数据库配置,仅对emoji表情包转码存储。
本方案对开源emoji表情包类库进行二次封装、自定义注解EmojiField、工具类EmojiUtil实现,emoji表情包快速转码处理。
工具类包结构如下图:
在这里插入图片描述
包括一个注解类@EmojiField、一个工具类EmojiUtil。EmojiUtil对emoji工具类库( https://github.com/vdurmont/emoji-java)进行二次封装,利用java反射特性对POJO对象中的某个string字段进行emoji表情包转码。

@EmojiFiled:

/*** @description: 指定指端做emoji字符转换* @author: luoping* @date: 2022/10/21**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EmojiField {}

POJO对象:

@ApiModel("资源基本信息")
@Data
public class TResourceBaseInfoVO {@ApiModelProperty("自增id")private Long id;@ApiModelProperty("资源名称")private String name;@ApiModelProperty("广告代码")@EmojiFieldprivate String codes;@ApiModelProperty("模板内容")@EmojiFieldprivate String templateContent;
}

EmojiUtil:

package xxx.xxx;import com.alibaba.fastjson.JSONObject;
import com.vdurmont.emoji.EmojiManager;
import com.vdurmont.emoji.EmojiParser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.util.StringUtil;import java.lang.reflect.Field;/*** @description: 表情包工具类* @author: luoping* @date: 2022/10/21**/
@Slf4j
public class EmojiUtil {/*** 将文本中的emoji表情包转码* @param emojiStr* @return*/public static String encode(String emojiStr) {if(StringUtil.isBlank(emojiStr)) {return null;}if(!EmojiManager.containsEmoji(emojiStr)) {return emojiStr;}return EmojiParser.parseToAliases(emojiStr);}/*** 将文本中的emoji表情(转码后)恢复成表情包* @param deEmojiStr* @return*/public static String decode(String deEmojiStr) {if(StringUtil.isBlank(deEmojiStr)) {return null;}
//        if(!EmojiManager.containsEmoji(deEmojiStr)) {
//            return deEmojiStr;
//        }return EmojiParser.parseToUnicode(deEmojiStr);}/*** 将对象中@EmojiField修饰的字符串进行emoji表情包转码* @param t* @param <T>*/public static <T> void encode(T t) {Field[] fields = t.getClass().getDeclaredFields();for (Field field : fields) {// 判断字段注解是否存在boolean annotationPresent = field.isAnnotationPresent(EmojiField.class);if (annotationPresent) {if(!StringUtils.equals(field.getType().getName(), "java.lang.String")) {// 只处理String类型continue;}// 将字段中包含emoji表情包的内容进行转码赋值field.setAccessible(true);try {String srcStr = (String)field.get(t);field.set(t, encode(srcStr));}catch (Exception e) {log.error("EmojiUtil encode error: {}", JSONObject.toJSONString(t), e);}field.setAccessible(false);}}}/*** 将对象中@EmojiField修饰的字符串进行emoji表情包解码* @param t* @param <T>*/public static <T> void decode(T t) {Field[] fields = t.getClass().getDeclaredFields();for (Field field : fields) {// 判断字段注解是否存在boolean annotationPresent = field.isAnnotationPresent(EmojiField.class);if (annotationPresent) {if(!StringUtils.equals(field.getType().getName(), "java.lang.String")) {// 只处理String类型continue;}// 将字段中包含emoji表情包的内容进行转码赋值field.setAccessible(true);try {String srcStr = (String)field.get(t);field.set(t, decode(srcStr));}catch (Exception e) {log.error("EmojiUtil decode error: {}", JSONObject.toJSONString(t), e);}field.setAccessible(false);}}}/*** 是否包含emoji表情包* @param str* @return*/public static boolean containEmoji(String str) {return EmojiManager.containsEmoji(str);}}

单元测试:

@Testpublic void testEmojiUtil() {TResourceBaseInfoAddReqVO vo = new TResourceBaseInfoAddReqVO();vo.setId(1000l);vo.setCodes("哈喽emoji😁");vo.setTemplateContent("😁💣");System.out.println("编码前:");System.out.println(JSONObject.toJSONString(vo));EmojiUtil.encode(vo);System.out.println("编码后:");System.out.println(JSONObject.toJSONString(vo));EmojiUtil.decode(vo);System.out.println("解码后:");System.out.println(JSONObject.toJSONString(vo));}

运行结果:
在这里插入图片描述


http://chatgpt.dhexx.cn/article/b2R8svnF.shtml

相关文章

有趣的表情包购物网站

首页 一个轮播图 首页 换肤 产品页 一个放大镜 我的账户界面 产品信息界面 一个打星小程序 可增删 以及删除的购物车界面

怎么自己制作动图表情包?在线gif生成的操作步骤

gif表情包在我们平时的生活里斗图的时候经常会用到&#xff0c;那么如何用图片制作gif&#xff08;https://www.gif.cn&#xff09;表情包呢&#xff1f;今天就分享一个在线gif生成的简单方法&#xff0c;利用gif制作工具将图片转gif动图&#xff0c;下面是详细的操作步骤。 打…

表情符号(emoji)大全,只此一文便够了

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 表情符号&#xff08;emoji&#xff09;大全、只此一文便够了 摘要集中展示笑脸和动物人庆贺和物品食品和物交通和地点符号 符号表smileys_and_peopleanimals_and_naturefood_and_dr…

热门聊天表情包怎么找?怎么制作?多平台表情合集,没有找不到的表情包!搞笑-金馆长-张家辉-卡通-二次元-gif等表情大全

去年的时候我做了一个表情包的小程序&#xff1a;i表情助手。 第一个版本做的比较简陋&#xff0c;一是表情图片资源比较少&#xff0c;二是需要用户填写文案制作&#xff0c;总的来说还是不够好用&#xff0c;所以一直没有进行推广。 过完年放完假回来&#xff0c;我决定好好…

22、实现发送文字、表情包

实现发送文字、表情包 一、 发送原理 二、 前端处理核心方法三、 后端逻辑处理函数 func dispatch(data[]byte)四、对端接收到消息后处理函数五、表情包简单逻辑六、发送图片流程七、 发送语音八、 发送视频测试 实现发送文字、表情包 一、 发送原理前端user1拼接好数据对象 …

是谁在Go标准库的源码中植入了色情网站?

昨天&#xff0c;有网友在群里说在GitHub上发现了色情网站&#xff01; GitHub上怎么会有色情网站呢&#xff1f;网友给出了下面的截图&#xff1a; 这个出现在Go标准库中的Issue里面&#xff0c;有一个url… 该Issue地址&#xff1a;https://github.com/golang/go/issues/488…

调皮的表情图(Emoji)

调皮的表情&#xff08;Emoji&#xff09; 示例HTMLCSSJS 更多有趣示例 尽在 知屋安砖社区 示例 HTML <div class"main"><div class"emoji"><div class"emoji__eyes abs"><div class"emoji__eye"></div&…

现表情包大幅流行,今天教你们开发个人表情包网站

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于腾讯云 作者&#xff1a;python学习教程 ( 想要学习Python&#xff1f;Python学习交流群&#xff1a;1039649593&#xff0c;满足你的需求…

python是世界上最好的语言表情包_语言表情包 - 语言微信表情包 - 语言QQ表情包 - 发表情 fabiaoqing.com...

如果你有一个朋友很久没跟你联系了一是他死了是他是学汉语言的三是他在期末考试如果他既是汉语言的又在准备期末考试你就当他死了吧 - 汉语言专业表情包 对方不想和你说话,向你推荐了世界上最好的语言!(PHP)_PHP_语言_对方表情 组织语言中(写作业中)_作业_语言_组织表情 …

情网

情网 我掩饰不住的慌张&#xff0c;在迫不急待地张望&#xff0c;生怕这一路是好梦一场。而你是一张无边无际的网&#xff0c;轻易就把我困在网中央&#xff0c;我越陷越深越迷惘&#xff0c;路越走越远越漫长&#xff0c;如何我才能锁住你眼光。情愿就这样守在你身旁&#xff…

javaScript基础面试题 -- 延迟加载JS有哪些方式?

延迟加载JS有哪些方式&#xff1f; js脚本放置在不同位置&#xff0c;对页面加载的不同影响defer与async的区别&#xff1a; 回答&#xff1a;defer 与 async js脚本放置在不同位置&#xff0c;对页面加载的不同影响 关于这个问题&#xff0c;首先来介绍一下&#xff0c;js脚本…

14道高频手写JS面试题及答案,巩固你的JS基础

目录 1. 手写深拷贝 2. 防抖函数 3. 节流函数 4. 模拟 instanceof 5. 全局通用的数据类型判断方法 6. 手写 call 函数 7. 手写 apply 函数 8. bind方法 9. 模拟 new 10. 类数组转化为数组的方法 11. 组合继承 12. 原型式继承 13. 实现 Object.create() 14. 数组…

javaScript基础面试题 --数据类型和考题

简单数据类型和复杂数据类型 简单类型&#xff08;基本数据类型、值类型&#xff09;&#xff1a;在存储时变量中存储的是值本身&#xff0c;包括string &#xff0c;number&#xff0c;boolean&#xff0c;undefined&#xff0c;null 复杂数据类型&#xff08;引用类型&…

分享一些常用的 JS 基础面试题

介绍 此篇属于前端算法入门系列的第一篇&#xff0c;主要介绍常用的数组方法、字符串方法、遍历方法、高阶函数、正则表达式以及相关数学知识。 前端算法入门一&#xff1a;刷算法题常用的JS基础扫盲[1]前端算法入门二&#xff1a;时间空间复杂度\&8大数据结构的JS实现[2]前…

js基础面试题总结

数据类型 什么是引用类型&#xff0c;值类型 值类型key与value的值存储再栈中&#xff08;量小&#xff09;医用类型再栈存储引用地址&#xff0c;在堆中存储数据&#xff08;量大&#xff09;把引用类型赋值给一个变量&#xff0c;是把变量的引用地址指向引用类型堆中地址 …

js基础常考面试题汇总(一)(附答案)

1.值类型和引用类型的区别 //值类型 let a 100 let b a a 200 console.log(b) //100 //引用类型 let a { age: 20 } let b a console.log(a.age) //21值类型&#xff1a;number, string, boolean, null, undefined, symbol(ES6)引用类型&#xff1a;Object(对象的子类: A…

3道js经典面试题

第一道&#xff1a; var a 10; // 全局作用域&#xff0c;全局变量。a10function foo() {// var a //的声明将被提升到到函数的顶部。// 比如:var aconsole.log(a); // 打印 undefined// 实际初始化值20只发生在这里var a 20; // local scope}foo(); 看图说话&#xff1a; 第…

2022年js基础面试题---持续更新

目录 1.javascipt的数据类型 1.1基本类型 1.2引用类型 1.3存储方式的区别 1.4 undefined和null的区别 1.5JavaScript什么情况下会返回undefined值&#xff1f; 2.javaScript数据类型检测的方法 2.1 typeof 2.2 instanceof 3.创建函数的几种方式 3.1 函数声明式 3.2…

JS 基础面试题

JS 基础面试题 1、什么是JavaScript&#xff1f; 基于对象和事件驱动可解释性脚本语言 2、JavaScript与ECMAScript的关系&#xff1f; JavaScript是ECMAScript的表现&#xff0c;ECMAScript是JavaScript的规范 3、变量的命名规则&#xff1f; 1.名字见名知义&#xff0c;…

js基础面试题

一、JavaScript的基本数据类型 1、 基本类型&#xff1a;字符串&#xff08;String&#xff09;、数字(Number)、布尔(Boolean)、对空&#xff08;Null&#xff09;、未定义&#xff08;Undefined&#xff09;、Symbol。 2、 引用数据类型&#xff1a;对象(Object)、数组(Arr…