解决文字和表情存储到msql数据库出现异常问题

异常:

Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\xA4\x97 \xF0...' for column 'name' at row 1
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2551)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
    at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1192)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:45)
    at com.sun.proxy.$Proxy21.execute(Unknown Source)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:23)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:51)
    at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:29)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:74)
    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:43)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:44)
    at com.sun.proxy.$Proxy20.update(Unknown Source)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:118)
    ... 61 more

异常原因:

数据库一般设置的编码格式是utf-8格式,而utf-8只包含3个字节编码,然而现在出现了4个字节编码格式,导致程序识别失败。

两种解决方法

1)把数据库编码格式设置成utf8mb4格式,其对应数据表也设置成其utf8mb4编码格式

2)直接过滤掉其多余的编码格式字节。使用其过滤工具类进行过滤,从而达到目的

public class UTF8Utils {

    public static Map<String, Integer> hexMap = new HashMap<String, Integer>();
    public static Map<String, Integer> byteMap = new HashMap<String, Integer>();

    static {
        hexMap.put("0", 2);
        hexMap.put("1", 2);
        hexMap.put("2", 2);
        hexMap.put("3", 2);
        hexMap.put("4", 2);
        hexMap.put("5", 2);
        hexMap.put("6", 2);
        hexMap.put("7", 2);
        hexMap.put("c", 4);
        hexMap.put("d", 4);
        hexMap.put("e", 6);
        hexMap.put("f", 8);

        byteMap.put("0", 1);
        byteMap.put("1", 1);
        byteMap.put("2", 1);
        byteMap.put("3", 1);
        byteMap.put("4", 1);
        byteMap.put("5", 1);
        byteMap.put("6", 1);
        byteMap.put("7", 1);
        byteMap.put("c", 2);
        byteMap.put("d", 2);
        byteMap.put("e", 3);
        byteMap.put("f", 4);
    }

    /**
     * 是否包含4字节UTF-8编码的字符(先转换16进制再判断)
     * @param s 字符串
     * @return 是否包含4字节UTF-8编码的字符
     */
    public static boolean contains4BytesChar(String s) {
        if (s == null || s.trim().length() == 0) {
            return false;
        }

        String hex = UTF8Utils.bytesToHex(s.getBytes());
//        System.out.println("full hex : " + hex);

        String firstChar = null;
        while (hex != null && hex.length() > 1) {
            firstChar = hex.substring(0, 1);
//            System.out.println("firstChar : " + firstChar);

            if ("f".equals(firstChar)) {
//                System.out.println("it is f start, it is 4 bytes, return.");
                return true;
            }

            if (hexMap.get(firstChar) == null) {
//                System.out.println("it is f start, it is 4 bytes, return.");
                // todo, throw exception for this case
                return false;
            }

            hex = hex.substring(hexMap.get(firstChar), hex.length());
//            System.out.println("remain hex : " + hex);
        }

        return false;
    }

    /**
     * 是否包含4字节UTF-8编码的字符
     * @param s 字符串
     * @return 是否包含4字节UTF-8编码的字符
     */
    public static boolean contains4BytesChar2(String s) {
        if (s == null || s.trim().length() == 0) {
            return false;
        }

        byte[] bytes = s.getBytes();

        if (bytes == null || bytes.length == 0) {
            return false;
        }

        int index = 0;
        byte b;
        String hex = null;
        String firstChar = null;
        int step;
        while (index <= bytes.length - 1) {
//            System.out.println("while loop, index : " + index);
            b = bytes[index];

            hex = byteToHex(b);
            if (hex == null || hex.length() < 2) {
//                System.out.println("fail to check whether contains 4 bytes char(1 byte hex char too short), default return false.");
                // todo, throw exception for this case
                return false;
            }

            firstChar = hex.substring(0, 1);

            if (firstChar.equals("f")) {
                return true;
            }

            if (byteMap.get(firstChar) == null) {
//                System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false.");
                // todo, throw exception for this case
                return false;
            }

            step = byteMap.get(firstChar);
//            System.out.println("while loop, index : " + index + ", step : " + step);
            index = index + step;
        }

        return false;
    }

    /**
     * 去除4字节UTF-8编码的字符
     * @param s 字符串
     * @return 已去除4字节UTF-8编码的字符
     */
    public static byte[] remove4BytesUTF8Char(String s) {
        byte[] bytes = s.getBytes();
        byte[] removedBytes = new byte[bytes.length];
        int index = 0;

        String hex = null;
        String firstChar = null;
        for (int i = 0; i < bytes.length; ) {
            hex = UTF8Utils.byteToHex(bytes[i]);

            if (hex == null || hex.length() < 2) {
//                System.out.println("fail to check whether contains 4 bytes char(1 byte hex char too short), default return false.");
                // todo, throw exception for this case
                return null;
            }

            firstChar = hex.substring(0, 1);

            if (byteMap.get(firstChar) == null) {
//                System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false.");
                // todo, throw exception for this case
                return null;
            }

            if (firstChar.equals("f")) {
                for (int j = 0; j < byteMap.get(firstChar); j++) {
                    i++;
                }
                continue;
            }

            for (int j = 0; j < byteMap.get(firstChar); j++) {
                removedBytes[index++] = bytes[i++];
            }
        }

        return Arrays.copyOfRange(removedBytes, 0, index);
    }

    /**
     * 将字符串的16进制转换为HEX,并按每个字符的16进制分隔格式化
     * @param s 字符串
     */
    public static String splitForReading(String s) {
        if (s == null || s.trim().length() == 0) {
            return "";
        }

        String hex = UTF8Utils.bytesToHex(s.getBytes());
//        System.out.println("full hex : " + hex);

        if (hex == null || hex.length() == 0) {
//            System.out.println("fail to translate the bytes to hex.");
            // todo, throw exception for this case
            return "";
        }

        StringBuilder sb = new StringBuilder();
        int index = 0;

        String firstChar = null;
        String splittedString = null;
        while (index < hex.length()) {
            firstChar = hex.substring(index, index + 1);

            if (hexMap.get(firstChar) == null) {
//                System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false.");
                // todo, throw exception for this case
                return "";
            }

            splittedString = hex.substring(index, index + hexMap.get(firstChar));
            sb.append(splittedString).append(" ");
            index = index + hexMap.get(firstChar);
        }

//        System.out.println("formated sb : " + sb);
        return sb.toString();
    }

    /**
     * 字节数组转十六进制
     * @param bytes 字节数组
     * @return 十六进制
     */
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            int r = bytes[i] & 0xFF;

            String hexResult = Integer.toHexString(r);
            if (hexResult.length() < 2) {
                sb.append(0); // 前补0
            }
            sb.append(hexResult);
        }

        return sb.toString();
    }

    /**
     * 字节转十六进制
     * @param b 字节
     * @return 十六进制
     */
    public static String byteToHex(byte b) {
        int r = b & 0xFF;//获得低8位
        String hexResult = Integer.toHexString(r);

        StringBuilder sb = new StringBuilder();
        if (hexResult.length() < 2) {
            sb.append(0); // 前补0
        }
        sb.append(hexResult);
        return sb.toString();
    }
}

转载于:https://my.oschina.net/u/2251646/blog/1030987

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值